diff --git a/submodules/TelegramCore/.gitignore b/submodules/TelegramCore/.gitignore new file mode 100644 index 0000000000..67641bcb90 --- /dev/null +++ b/submodules/TelegramCore/.gitignore @@ -0,0 +1,25 @@ +fastlane/README.md +fastlane/report.xml +fastlane/test_output/* +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.xcscmblueprint +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +.DS_Store +*.dSYM +*.dSYM.zip +*.ipa +*/xcuserdata/* +TelegramCore.xcodeproj/* diff --git a/submodules/TelegramCore/BUCK b/submodules/TelegramCore/BUCK new file mode 100644 index 0000000000..082b468dfc --- /dev/null +++ b/submodules/TelegramCore/BUCK @@ -0,0 +1,44 @@ +load('//tools:buck_utils.bzl', 'config_with_updated_linker_flags', 'configs_with_config', 'combined_config') +load('//tools:buck_defs.bzl', 'SHARED_CONFIGS', 'EXTENSION_LIB_SPECIFIC_CONFIG') + +apple_library( + name = 'TelegramCorePrivateModule', + srcs = glob([ + 'TelegramCore/**/*.m', + 'TelegramCore/**/*.c', + 'third-party/libphonenumber-iOS/*.m', + ]), + headers = glob([ + 'TelegramCore/**/*.h', + 'third-party/libphonenumber-iOS/*.h', + ]), + header_namespace = 'TelegramCorePrivateModule', + exported_headers = glob([ + 'TelegramCore/**/*.h', + 'third-party/libphonenumber-iOS/*.h', + ], exclude = ['TelegramCore/TelegramCore.h']), + modular = True, + visibility = ['//submodules/TelegramCore:TelegramCore'], + deps = [ + '//submodules/MtProtoKit:MtProtoKit', + ], +) + +apple_library( + name = 'TelegramCore', + srcs = glob([ + 'TelegramCore/**/*.swift' + ]), + configs = configs_with_config(combined_config([SHARED_CONFIGS, EXTENSION_LIB_SPECIFIC_CONFIG])), + swift_compiler_flags = [ + '-suppress-warnings', + '-application-extension', + ], + visibility = ['PUBLIC'], + deps = [ + ':TelegramCorePrivateModule', + '//submodules/SSignalKit:SwiftSignalKit', + '//submodules/MtProtoKit:MtProtoKit', + '//submodules/Postbox:Postbox', + ], +) diff --git a/submodules/TelegramCore/TelegramCore/AccessSecureId.swift b/submodules/TelegramCore/TelegramCore/AccessSecureId.swift new file mode 100644 index 0000000000..e840522c19 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccessSecureId.swift @@ -0,0 +1,194 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +import TelegramCorePrivateModule + +private enum GenerateSecureSecretError { + case generic +} + +func encryptSecureData(key: Data, iv: Data, data: Data, decrypt: Bool) -> Data? { + if data.count % 16 != 0 { + return nil + } + + return CryptoAES(!decrypt, key, iv, data) +} + +func verifySecureSecret(_ data: Data) -> Bool { + guard data.withUnsafeBytes({ (bytes: UnsafePointer) -> Bool in + var checksum: UInt32 = 0 + for i in 0 ..< data.count { + checksum += UInt32(bytes.advanced(by: i).pointee) + checksum = checksum % 255 + } + if checksum == 239 { + return true + } else { + return false + } + }) else { + return false + } + return true +} + +func decryptedSecureSecret(encryptedSecretData: Data, password: String, derivation: TwoStepSecurePasswordDerivation, id: Int64) -> Data? { + guard let passwordHash = securePasswordKDF(password: password, derivation: derivation) else { + return nil + } + + let secretKey = passwordHash.subdata(in: 0 ..< 32) + let iv = passwordHash.subdata(in: 32 ..< (32 + 16)) + + guard let decryptedSecret = CryptoAES(false, secretKey, iv, encryptedSecretData) else { + return nil + } + + if !verifySecureSecret(decryptedSecret) { + return nil + } + + let secretHashData = sha256Digest(decryptedSecret) + var secretId: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretId, bytes, 8) + } + + if secretId != id { + return nil + } + + return decryptedSecret +} + +func encryptedSecureSecret(secretData: Data, password: String, inputDerivation: TwoStepSecurePasswordDerivation) -> (data: Data, salt: TwoStepSecurePasswordDerivation, id: Int64)? { + let secretHashData = sha256Digest(secretData) + var secretId: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretId, bytes, 8) + } + + guard let (passwordHash, updatedDerivation) = securePasswordUpdateKDF(password: password, derivation: inputDerivation) else { + return nil + } + + let secretKey = passwordHash.subdata(in: 0 ..< 32) + let iv = passwordHash.subdata(in: 32 ..< (32 + 16)) + + guard let encryptedSecret = CryptoAES(true, secretKey, iv, secretData) else { + return nil + } + + if decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: password, derivation: updatedDerivation, id: secretId) != secretData { + return nil + } + + return (encryptedSecret, updatedDerivation, secretId) +} + +func generateSecureSecretData() -> Data? { + var secretData = Data(count: 32) + let secretDataCount = secretData.count + + guard secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in + let copyResult = SecRandomCopyBytes(nil, 32, bytes) + return copyResult == errSecSuccess + }) else { + return nil + } + + secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) in + while true { + var checksum: UInt32 = 0 + for i in 0 ..< secretDataCount { + checksum += UInt32(bytes.advanced(by: i).pointee) + checksum = checksum % 255 + } + if checksum == 239 { + break + } else { + var i = secretDataCount - 1 + inner: while i >= 0 { + var byte = bytes.advanced(by: i).pointee + if byte != 0xff { + byte += 1 + bytes.advanced(by: i).pointee = byte + break inner + } else { + byte = 0 + bytes.advanced(by: i).pointee = byte + } + i -= 1 + } + } + } + }) + return secretData +} + +private func generateSecureSecret(network: Network, password: String) -> Signal { + guard let secretData = generateSecureSecretData() else { + return .fail(.generic) + } + + return updateTwoStepVerificationSecureSecret(network: network, password: password, secret: secretData) + |> mapError { _ -> GenerateSecureSecretError in + return .generic + } + |> map { _ -> Data in + return secretData + } +} + +public struct SecureIdAccessContext: Equatable { + let secret: Data + let id: Int64 +} + +public enum SecureIdAccessError { + case generic + case passwordError(AuthorizationPasswordVerificationError) + case secretPasswordMismatch +} + +public func accessSecureId(network: Network, password: String) -> Signal<(context: SecureIdAccessContext, settings: TwoStepVerificationSettings), SecureIdAccessError> { + return requestTwoStepVerifiationSettings(network: network, password: password) + |> mapError { error -> SecureIdAccessError in + return .passwordError(error) + } + |> mapToSignal { settings -> Signal<(context: SecureIdAccessContext, settings: TwoStepVerificationSettings), SecureIdAccessError> in + if let secureSecret = settings.secureSecret { + if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: secureSecret.data, password: password, derivation: secureSecret.derivation, id: secureSecret.id) { + return .single((SecureIdAccessContext(secret: decryptedSecret, id: secureSecret.id), settings)) + } else { + return .fail(.secretPasswordMismatch) + } + } else { + return generateSecureSecret(network: network, password: password) + |> mapError { _ -> SecureIdAccessError in + return SecureIdAccessError.generic + } + |> map { decryptedSecret in + let secretHashData = sha256Digest(decryptedSecret) + var secretId: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretId, bytes, 8) + } + return (SecureIdAccessContext(secret: decryptedSecret, id: secretId), settings) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Account.swift b/submodules/TelegramCore/TelegramCore/Account.swift new file mode 100644 index 0000000000..15cd2e8bcb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Account.swift @@ -0,0 +1,1445 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import UIKit +#endif +import TelegramCorePrivateModule + +public protocol AccountState: PostboxCoding { + func equalsTo(_ other: AccountState) -> Bool +} + +public func ==(lhs: AccountState, rhs: AccountState) -> Bool { + return lhs.equalsTo(rhs) +} + +public class AuthorizedAccountState: AccountState { + public final class State: PostboxCoding, Equatable, CustomStringConvertible { + let pts: Int32 + let qts: Int32 + let date: Int32 + let seq: Int32 + + init(pts: Int32, qts: Int32, date: Int32, seq: Int32) { + self.pts = pts + self.qts = qts + self.date = date + self.seq = seq + } + + public init(decoder: PostboxDecoder) { + self.pts = decoder.decodeInt32ForKey("pts", orElse: 0) + self.qts = decoder.decodeInt32ForKey("qts", orElse: 0) + self.date = decoder.decodeInt32ForKey("date", orElse: 0) + self.seq = decoder.decodeInt32ForKey("seq", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.pts, forKey: "pts") + encoder.encodeInt32(self.qts, forKey: "qts") + encoder.encodeInt32(self.date, forKey: "date") + encoder.encodeInt32(self.seq, forKey: "seq") + } + + public var description: String { + return "(pts: \(pts), qts: \(qts), seq: \(seq), date: \(date))" + } + } + + let isTestingEnvironment: Bool + let masterDatacenterId: Int32 + let peerId: PeerId + + let state: State? + + public required init(decoder: PostboxDecoder) { + self.isTestingEnvironment = decoder.decodeInt32ForKey("isTestingEnvironment", orElse: 0) != 0 + self.masterDatacenterId = decoder.decodeInt32ForKey("masterDatacenterId", orElse: 0) + self.peerId = PeerId(decoder.decodeInt64ForKey("peerId", orElse: 0)) + self.state = decoder.decodeObjectForKey("state", decoder: { return State(decoder: $0) }) as? State + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.isTestingEnvironment ? 1 : 0, forKey: "isTestingEnvironment") + encoder.encodeInt32(self.masterDatacenterId, forKey: "masterDatacenterId") + encoder.encodeInt64(self.peerId.toInt64(), forKey: "peerId") + if let state = self.state { + encoder.encodeObject(state, forKey: "state") + } + } + + public init(isTestingEnvironment: Bool, masterDatacenterId: Int32, peerId: PeerId, state: State?) { + self.isTestingEnvironment = isTestingEnvironment + self.masterDatacenterId = masterDatacenterId + self.peerId = peerId + self.state = state + } + + func changedState(_ state: State) -> AuthorizedAccountState { + return AuthorizedAccountState(isTestingEnvironment: self.isTestingEnvironment, masterDatacenterId: self.masterDatacenterId, peerId: self.peerId, state: state) + } + + public func equalsTo(_ other: AccountState) -> Bool { + if let other = other as? AuthorizedAccountState { + return self.isTestingEnvironment == other.isTestingEnvironment && self.masterDatacenterId == other.masterDatacenterId && + self.peerId == other.peerId && + self.state == other.state + } else { + return false + } + } +} + +public func ==(lhs: AuthorizedAccountState.State, rhs: AuthorizedAccountState.State) -> Bool { + return lhs.pts == rhs.pts && + lhs.qts == rhs.qts && + lhs.date == rhs.date && + lhs.seq == rhs.seq +} + +private let accountRecordToActiveKeychainId = Atomic<[AccountRecordId: Int]>(value: [:]) + +private func makeExclusiveKeychain(id: AccountRecordId, postbox: Postbox) -> Keychain { + var keychainId = 0 + let _ = accountRecordToActiveKeychainId.modify { dict in + var dict = dict + if let value = dict[id] { + dict[id] = value + 1 + keychainId = value + 1 + } else { + keychainId = 0 + dict[id] = 0 + } + return dict + } + return Keychain(get: { key in + let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in + return dict[id] == keychainId + } + if enabled { + return postbox.keychainEntryForKey(key) + } else { + Logger.shared.log("Keychain", "couldn't get \(key) — not current") + return nil + } + }, set: { (key, data) in + let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in + return dict[id] == keychainId + } + if enabled { + postbox.setKeychainEntryForKey(key, value: data) + } else { + Logger.shared.log("Keychain", "couldn't set \(key) — not current") + } + }, remove: { key in + let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in + return dict[id] == keychainId + } + if enabled { + postbox.removeKeychainEntryForKey(key) + } else { + Logger.shared.log("Keychain", "couldn't remove \(key) — not current") + } + }) +} + +public class UnauthorizedAccount { + public let networkArguments: NetworkInitializationArguments + public let id: AccountRecordId + public let rootPath: String + public let basePath: String + public let testingEnvironment: Bool + public let postbox: Postbox + public let network: Network + + public var masterDatacenterId: Int32 { + return Int32(self.network.mtProto.datacenterId) + } + + public let shouldBeServiceTaskMaster = Promise() + + init(networkArguments: NetworkInitializationArguments, id: AccountRecordId, rootPath: String, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, shouldKeepAutoConnection: Bool = true) { + self.networkArguments = networkArguments + self.id = id + self.rootPath = rootPath + self.basePath = basePath + self.testingEnvironment = testingEnvironment + self.postbox = postbox + self.network = network + + network.shouldKeepConnection.set(self.shouldBeServiceTaskMaster.get() + |> map { mode -> Bool in + switch mode { + case .now, .always: + return true + case .never: + return false + } + }) + + network.context.performBatchUpdates({ + var datacenterIds: [Int] = [1, 2] + if !testingEnvironment { + datacenterIds.append(contentsOf: [4]) + } + for id in datacenterIds { + if network.context.authInfoForDatacenter(withId: id) == nil { + network.context.authInfoForDatacenter(withIdRequired: id, isCdn: false) + } + } + network.context.beginExplicitBackupAddressDiscovery() + }) + } + + public func changedMasterDatacenterId(accountManager: AccountManager, masterDatacenterId: Int32) -> Signal { + if masterDatacenterId == Int32(self.network.mtProto.datacenterId) { + return .single(self) + } else { + let keychain = makeExclusiveKeychain(id: self.id, postbox: self.postbox) + + return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in + return (transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings) as? ProxySettings) + } + |> mapToSignal { localizationSettings, proxySettings -> Signal<(LocalizationSettings?, ProxySettings?, NetworkSettings?), NoError> in + return self.postbox.transaction { transaction -> (LocalizationSettings?, ProxySettings?, NetworkSettings?) in + return (localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings) + } + } + |> mapToSignal { (localizationSettings, proxySettings, networkSettings) -> Signal in + return initializedNetwork(arguments: self.networkArguments, supplementary: false, datacenterId: Int(masterDatacenterId), keychain: keychain, basePath: self.basePath, testingEnvironment: self.testingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil) + |> map { network in + let updated = UnauthorizedAccount(networkArguments: self.networkArguments, id: self.id, rootPath: self.rootPath, basePath: self.basePath, testingEnvironment: self.testingEnvironment, postbox: self.postbox, network: network) + updated.shouldBeServiceTaskMaster.set(self.shouldBeServiceTaskMaster.get()) + return updated + } + } + } + } +} + +func accountNetworkUsageInfoPath(basePath: String) -> String { + return basePath + "/network-usage" +} + +public func accountRecordIdPathName(_ id: AccountRecordId) -> String { + return "account-\(UInt64(bitPattern: id.int64))" +} + +public enum AccountResult { + case upgrading(Float) + case unauthorized(UnauthorizedAccount) + case authorized(Account) +} + +let telegramPostboxSeedConfiguration: SeedConfiguration = { + var messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]] = [:] + for peerNamespace in peerIdNamespacesWithInitialCloudMessageHoles { + messageHoles[peerNamespace] = [ + Namespaces.Message.Cloud: Set(MessageTags.all) + ] + } + + var globalMessageIdsPeerIdNamespaces = Set() + for peerIdNamespace in [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup] { + globalMessageIdsPeerIdNamespaces.insert(GlobalMessageIdsNamespace(peerIdNamespace: peerIdNamespace, messageIdNamespace: Namespaces.Message.Cloud)) + } + + return SeedConfiguration(globalMessageIdsPeerIdNamespaces: globalMessageIdsPeerIdNamespaces, initializeChatListWithHole: (topLevel: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)), groups: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1))), messageHoles: messageHoles, existingMessageTags: MessageTags.all, messageTagsWithSummary: MessageTags.unseenPersonalMessage, existingGlobalMessageTags: GlobalMessageTags.all, peerNamespacesRequiringMessageTextIndex: [Namespaces.Peer.SecretChat], peerSummaryCounterTags: { peer in + if let peer = peer as? TelegramChannel { + switch peer.info { + case .group: + if let addressName = peer.addressName, !addressName.isEmpty { + return [.publicGroups] + } else { + return [.regularChatsAndPrivateGroups] + } + case .broadcast: + return [.channels] + } + } else { + return [.regularChatsAndPrivateGroups] + } + }, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)]) +}() + +public enum AccountPreferenceEntriesResult { + case progress(Float) + case result(String, [ValueBoxKey: PreferencesEntry]) +} + +public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + return postbox + |> mapToSignal { value -> Signal in + switch value { + case let .upgrading(progress): + return .single(.progress(progress)) + case let .postbox(postbox): + return postbox.transaction { transaction -> AccountPreferenceEntriesResult in + var result: [ValueBoxKey: PreferencesEntry] = [:] + for key in keys { + if let value = transaction.getPreferencesEntry(key: key) { + result[key] = value + } + } + return .result(path, result) + } + } + } +} + +public enum AccountNoticeEntriesResult { + case progress(Float) + case result(String, [ValueBoxKey: NoticeEntry]) +} + +public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + return postbox + |> mapToSignal { value -> Signal in + switch value { + case let .upgrading(progress): + return .single(.progress(progress)) + case let .postbox(postbox): + return postbox.transaction { transaction -> AccountNoticeEntriesResult in + return .result(path, transaction.getAllNoticeEntries()) + } + } + } +} + +public enum LegacyAccessChallengeDataResult { + case progress(Float) + case result(PostboxAccessChallengeData) +} + +public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + return postbox + |> mapToSignal { value -> Signal in + switch value { + case let .upgrading(progress): + return .single(.progress(progress)) + case let .postbox(postbox): + return postbox.transaction { transaction -> LegacyAccessChallengeDataResult in + return .result(transaction.legacyGetAccessChallengeData()) + } + } + } +} + +public func accountTransaction(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, transaction: @escaping (Transaction) -> T) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + return postbox + |> mapToSignal { value -> Signal in + switch value { + case let .postbox(postbox): + return postbox.transaction(transaction) + default: + return .complete() + } + } +} + +public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + + return postbox + |> mapToSignal { result -> Signal in + switch result { + case let .upgrading(progress): + return .single(.upgrading(progress)) + case let .postbox(postbox): + return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in + return (transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings) as? ProxySettings) + } + |> mapToSignal { localizationSettings, proxySettings -> Signal in + return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in + var state = transaction.getState() + if state == nil, let backupData = backupData { + let backupState = AuthorizedAccountState(isTestingEnvironment: beginWithTestingEnvironment, masterDatacenterId: backupData.masterDatacenterId, peerId: PeerId(backupData.peerId), state: nil) + state = backupState + let dict = NSMutableDictionary() + dict.setObject(MTDatacenterAuthInfo(authKey: backupData.masterDatacenterKey, authKeyId: backupData.masterDatacenterKeyId, saltSet: [], authKeyAttributes: [:], mainTempAuthKey: nil, mediaTempAuthKey: nil), forKey: backupData.masterDatacenterId as NSNumber) + let data = NSKeyedArchiver.archivedData(withRootObject: dict) + transaction.setState(backupState) + transaction.setKeychainEntry(data, forKey: "persistent:datacenterAuthInfoById") + } + + return (state, localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings) + } + |> mapToSignal { (accountState, localizationSettings, proxySettings, networkSettings) -> Signal in + let keychain = makeExclusiveKeychain(id: id, postbox: postbox) + + if let accountState = accountState { + switch accountState { + case let unauthorizedState as UnauthorizedAccountState: + return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil) + |> map { network -> AccountResult in + return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: unauthorizedState.isTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + } + case let authorizedState as AuthorizedAccountState: + return postbox.transaction { transaction -> String? in + return (transaction.getPeer(authorizedState.peerId) as? TelegramUser)?.phone + } + |> mapToSignal { phoneNumber in + return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: phoneNumber) + |> map { network -> AccountResult in + return .authorized(Account(accountManager: accountManager, id: id, basePath: path, testingEnvironment: authorizedState.isTestingEnvironment, postbox: postbox, network: network, networkArguments: networkArguments, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods, supplementary: supplementary)) + } + } + case _: + assertionFailure("Unexpected accountState \(accountState)") + } + } + + return initializedNetwork(arguments: networkArguments, supplementary: supplementary, datacenterId: 2, keychain: keychain, basePath: path, testingEnvironment: beginWithTestingEnvironment, languageCode: localizationSettings?.primaryComponent.languageCode, proxySettings: proxySettings, networkSettings: networkSettings, phoneNumber: nil) + |> map { network -> AccountResult in + return .unauthorized(UnauthorizedAccount(networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: beginWithTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) + } + } + } + } + } +} + +public enum TwoStepPasswordDerivation { + case unknown + case sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: Data, salt2: Data, iterations: Int32, g: Int32, p: Data) + + fileprivate init(_ apiAlgo: Api.PasswordKdfAlgo) { + switch apiAlgo { + case .passwordKdfAlgoUnknown: + self = .unknown + case let .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1, salt2, g, p): + self = .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: salt1.makeData(), salt2: salt2.makeData(), iterations: 100000, g: g, p: p.makeData()) + } + } + + var apiAlgo: Api.PasswordKdfAlgo { + switch self { + case .unknown: + return .passwordKdfAlgoUnknown + case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, g, p): + precondition(iterations == 100000) + return .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: Buffer(data: salt1), salt2: Buffer(data: salt2), g: g, p: Buffer(data: p)) + } + } +} + +public enum TwoStepSecurePasswordDerivation { + case unknown + case sha512(salt: Data) + case PBKDF2_HMAC_sha512(salt: Data, iterations: Int32) + + init(_ apiAlgo: Api.SecurePasswordKdfAlgo) { + switch apiAlgo { + case .securePasswordKdfAlgoUnknown: + self = .unknown + case let .securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt): + self = .PBKDF2_HMAC_sha512(salt: salt.makeData(), iterations: 100000) + case let .securePasswordKdfAlgoSHA512(salt): + self = .sha512(salt: salt.makeData()) + } + } + + var apiAlgo: Api.SecurePasswordKdfAlgo { + switch self { + case .unknown: + return .securePasswordKdfAlgoUnknown + case let .PBKDF2_HMAC_sha512(salt, iterations): + precondition(iterations == 100000) + return .securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt: Buffer(data: salt)) + case let .sha512(salt): + return .securePasswordKdfAlgoSHA512(salt: Buffer(data: salt)) + } + } +} + +public struct TwoStepSRPSessionData { + public let id: Int64 + public let B: Data +} + +public struct TwoStepAuthData { + public let nextPasswordDerivation: TwoStepPasswordDerivation + public let currentPasswordDerivation: TwoStepPasswordDerivation? + public let srpSessionData: TwoStepSRPSessionData? + public let hasRecovery: Bool + public let hasSecretValues: Bool + public let currentHint: String? + public let unconfirmedEmailPattern: String? + public let secretRandom: Data + public let nextSecurePasswordDerivation: TwoStepSecurePasswordDerivation +} + +public func twoStepAuthData(_ network: Network) -> Signal { + return network.request(Api.functions.account.getPassword()) + |> map { config -> TwoStepAuthData in + switch config { + case let .password(flags, currentAlgo, srpB, srpId, hint, emailUnconfirmedPattern, newAlgo, newSecureAlgo, secureRandom): + let hasRecovery = (flags & (1 << 0)) != 0 + let hasSecureValues = (flags & (1 << 1)) != 0 + + let currentDerivation = currentAlgo.flatMap(TwoStepPasswordDerivation.init) + let nextDerivation = TwoStepPasswordDerivation(newAlgo) + let nextSecureDerivation = TwoStepSecurePasswordDerivation(newSecureAlgo) + + switch nextSecureDerivation { + case .unknown: + break + case .PBKDF2_HMAC_sha512: + break + case .sha512: + preconditionFailure() + } + + var srpSessionData: TwoStepSRPSessionData? + if let srpB = srpB, let srpId = srpId { + srpSessionData = TwoStepSRPSessionData(id: srpId, B: srpB.makeData()) + } + + return TwoStepAuthData(nextPasswordDerivation: nextDerivation, currentPasswordDerivation: currentDerivation, srpSessionData: srpSessionData, hasRecovery: hasRecovery, hasSecretValues: hasSecureValues, currentHint: hint, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secureRandom.makeData(), nextSecurePasswordDerivation: nextSecureDerivation) + } + } +} + +public func hexString(_ data: Data) -> String { + let hexString = NSMutableString() + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + for i in 0 ..< data.count { + hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee)) + } + } + + return hexString as String +} + +public func dataWithHexString(_ string: String) -> Data { + var hex = string + if hex.count % 2 != 0 { + return Data() + } + var data = Data() + while hex.count > 0 { + let subIndex = hex.index(hex.startIndex, offsetBy: 2) + let c = String(hex[.. Data { + return data.withUnsafeBytes { bytes -> Data in + return CryptoSHA1(bytes, Int32(data.count)) + } +} + +func sha256Digest(_ data : Data) -> Data { + return data.withUnsafeBytes { bytes -> Data in + return CryptoSHA256(bytes, Int32(data.count)) + } +} + +func sha512Digest(_ data : Data) -> Data { + return data.withUnsafeBytes { bytes -> Data in + return CryptoSHA512(bytes, Int32(data.count)) + } +} + +func passwordUpdateKDF(password: String, derivation: TwoStepPasswordDerivation) -> (Data, TwoStepPasswordDerivation)? { + guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { + return nil + } + + switch derivation { + case .unknown: + return nil + case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, gValue, p): + var nextSalt1 = salt1 + var randomSalt1 = Data() + randomSalt1.count = 32 + randomSalt1.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, 32) + } + nextSalt1.append(randomSalt1) + + let nextSalt2 = salt2 + + var g = Data(count: 4) + g.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + var gValue = gValue + withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in + let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! + for i in 0 ..< 4 { + bytes.advanced(by: i).pointee = sourceBytes.advanced(by: 4 - i - 1).pointee + } + }) + } + + let pbkdfInnerData = sha256Digest(nextSalt2 + sha256Digest(nextSalt1 + passwordData + nextSalt1) + nextSalt2) + + guard let pbkdfResult = MTPBKDF2(pbkdfInnerData, nextSalt1, iterations) else { + return nil + } + + let x = sha256Digest(nextSalt2 + pbkdfResult + nextSalt2) + + let gx = MTExp(g, x, p)! + + return (gx, .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: nextSalt1, salt2: nextSalt2, iterations: iterations, g: gValue, p: p)) + } +} + +struct PasswordKDFResult { + let id: Int64 + let A: Data + let M1: Data +} + +private func paddedToLength(what: Data, to: Data) -> Data { + if what.count < to.count { + var what = what + for _ in 0 ..< to.count - what.count { + what.insert(0, at: 0) + } + return what + } else { + return what + } +} + +private func paddedXor(_ a: Data, _ b: Data) -> Data { + let count = max(a.count, b.count) + var a = a + var b = b + while a.count < count { + a.insert(0, at: 0) + } + while b.count < count { + b.insert(0, at: 0) + } + a.withUnsafeMutableBytes { (aBytes: UnsafeMutablePointer) -> Void in + b.withUnsafeBytes { (bBytes: UnsafePointer) -> Void in + for i in 0 ..< count { + aBytes.advanced(by: i).pointee = aBytes.advanced(by: i).pointee ^ bBytes.advanced(by: i).pointee + } + } + } + return a +} + +func passwordKDF(password: String, derivation: TwoStepPasswordDerivation, srpSessionData: TwoStepSRPSessionData) -> PasswordKDFResult? { + guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { + return nil + } + + switch derivation { + case .unknown: + return nil + case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, gValue, p): + var a = Data(count: p.count) + let aLength = a.count + a.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + let _ = SecRandomCopyBytes(nil, aLength, bytes) + } + + var g = Data(count: 4) + g.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + var gValue = gValue + withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in + let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! + for i in 0 ..< 4 { + bytes.advanced(by: i).pointee = sourceBytes.advanced(by: 4 - i - 1).pointee + } + }) + } + + if !MTCheckIsSafeB(srpSessionData.B, p) { + return nil + } + + let B = paddedToLength(what: srpSessionData.B, to: p) + let A = paddedToLength(what: MTExp(g, a, p)!, to: p) + let u = sha256Digest(A + B) + + if MTIsZero(u) { + return nil + } + + let pbkdfInnerData = sha256Digest(salt2 + sha256Digest(salt1 + passwordData + salt1) + salt2) + + guard let pbkdfResult = MTPBKDF2(pbkdfInnerData, salt1, iterations) else { + return nil + } + + let x = sha256Digest(salt2 + pbkdfResult + salt2) + + let gx = MTExp(g, x, p)! + + let k = sha256Digest(p + paddedToLength(what: g, to: p)) + + let s1 = MTModSub(B, MTModMul(k, gx, p)!, p)! + + if !MTCheckIsSafeGAOrB(s1, p) { + return nil + } + + let s2 = MTAdd(a, MTMul(u, x)!)! + let S = MTExp(s1, s2, p)! + let K = sha256Digest(paddedToLength(what: S, to: p)) + let m1 = paddedXor(sha256Digest(p), sha256Digest(paddedToLength(what: g, to: p))) + let m2 = sha256Digest(salt1) + let m3 = sha256Digest(salt2) + let M = sha256Digest(m1 + m2 + m3 + A + B + K) + + return PasswordKDFResult(id: srpSessionData.id, A: A, M1: M) + } +} + +func securePasswordUpdateKDF(password: String, derivation: TwoStepSecurePasswordDerivation) -> (Data, TwoStepSecurePasswordDerivation)? { + guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { + return nil + } + + switch derivation { + case .unknown: + return nil + case let .sha512(salt): + var nextSalt = salt + var randomSalt = Data() + randomSalt.count = 32 + randomSalt.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, 32) + } + nextSalt.append(randomSalt) + + var data = Data() + data.append(nextSalt) + data.append(passwordData) + data.append(nextSalt) + return (sha512Digest(data), .sha512(salt: nextSalt)) + case let .PBKDF2_HMAC_sha512(salt, iterations): + var nextSalt = salt + var randomSalt = Data() + randomSalt.count = 32 + randomSalt.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, 32) + } + nextSalt.append(randomSalt) + + guard let passwordHash = MTPBKDF2(passwordData, nextSalt, iterations) else { + return nil + } + return (passwordHash, .PBKDF2_HMAC_sha512(salt: nextSalt, iterations: iterations)) + } +} + +func securePasswordKDF(password: String, derivation: TwoStepSecurePasswordDerivation) -> Data? { + guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { + return nil + } + + switch derivation { + case .unknown: + return nil + case let .sha512(salt): + var data = Data() + data.append(salt) + data.append(passwordData) + data.append(salt) + return sha512Digest(data) + case let .PBKDF2_HMAC_sha512(salt, iterations): + guard let passwordHash = MTPBKDF2(passwordData, salt, iterations) else { + return nil + } + return passwordHash + } +} + +func verifyPassword(_ account: UnauthorizedAccount, password: String) -> Signal { + return twoStepAuthData(account.network) + |> mapToSignal { authData -> Signal in + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { + return .fail(MTRpcError(errorCode: 400, errorDescription: "INTERNAL_NO_PASSWORD")) + } + + let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) + + if let kdfResult = kdfResult { + return account.network.request(Api.functions.auth.checkPassword(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false) + } else { + return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR")) + } + } +} + +public enum AccountServiceTaskMasterMode { + case now + case always + case never +} + +public struct AccountNetworkProxyState: Equatable { + public let address: String + public let hasConnectionIssues: Bool +} + +public enum AccountNetworkState: Equatable { + case waitingForNetwork + case connecting(proxy: AccountNetworkProxyState?) + case updating(proxy: AccountNetworkProxyState?) + case online(proxy: AccountNetworkProxyState?) +} + +public final class AccountAuxiliaryMethods { + public let updatePeerChatInputState: (PeerChatInterfaceState?, SynchronizeableChatInputState?) -> PeerChatInterfaceState? + public let fetchResource: (Account, MediaResource, Signal<[(Range, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal? + public let fetchResourceMediaReferenceHash: (MediaResource) -> Signal + public let prepareSecretThumbnailData: (MediaResourceData) -> (CGSize, Data)? + + public init(updatePeerChatInputState: @escaping (PeerChatInterfaceState?, SynchronizeableChatInputState?) -> PeerChatInterfaceState?, fetchResource: @escaping (Account, MediaResource, Signal<[(Range, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal?, fetchResourceMediaReferenceHash: @escaping (MediaResource) -> Signal, prepareSecretThumbnailData: @escaping (MediaResourceData) -> (CGSize, Data)?) { + self.updatePeerChatInputState = updatePeerChatInputState + self.fetchResource = fetchResource + self.fetchResourceMediaReferenceHash = fetchResourceMediaReferenceHash + self.prepareSecretThumbnailData = prepareSecretThumbnailData + } +} + +public struct AccountRunningImportantTasks: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let other = AccountRunningImportantTasks(rawValue: 1 << 0) + public static let pendingMessages = AccountRunningImportantTasks(rawValue: 1 << 1) +} + +public struct MasterNotificationKey: Codable { + public let id: Data + public let data: Data +} + +public func masterNotificationsKey(account: Account, ignoreDisabled: Bool) -> Signal { + return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: ignoreDisabled) +} + +private func masterNotificationsKey(masterNotificationKeyValue: Atomic, postbox: Postbox, ignoreDisabled: Bool) -> Signal { + if let key = masterNotificationKeyValue.with({ $0 }) { + return .single(key) + } + + return postbox.transaction(ignoreDisabled: ignoreDisabled, { transaction -> MasterNotificationKey in + if let value = transaction.keychainEntryForKey("master-notification-secret"), !value.isEmpty { + let authKeyHash = sha1Digest(value) + let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count) + let keyData = MasterNotificationKey(id: authKeyId, data: value) + let _ = masterNotificationKeyValue.swap(keyData) + return keyData + } else { + var secretData = Data(count: 256) + let secretDataCount = secretData.count + if !secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in + let copyResult = SecRandomCopyBytes(nil, secretDataCount, bytes) + return copyResult == errSecSuccess + }) { + assertionFailure() + } + + transaction.setKeychainEntry(secretData, forKey: "master-notification-secret") + let authKeyHash = sha1Digest(secretData) + let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count) + let keyData = MasterNotificationKey(id: authKeyId, data: secretData) + let _ = masterNotificationKeyValue.swap(keyData) + return keyData + } + }) +} + +public func decryptedNotificationPayload(key: MasterNotificationKey, data: Data) -> Data? { + if data.count < 8 { + return nil + } + + if data.subdata(in: 0 ..< 8) != key.id { + return nil + } + + let x = 8 + let msgKey = data.subdata(in: 8 ..< (8 + 16)) + let rawData = data.subdata(in: (8 + 16) ..< data.count) + let sha256_a = sha256Digest(msgKey + key.data.subdata(in: x ..< (x + 36))) + let sha256_b = sha256Digest(key.data.subdata(in: (40 + x) ..< (40 + x + 36)) + msgKey) + let aesKey = sha256_a.subdata(in: 0 ..< 8) + sha256_b.subdata(in: 8 ..< (8 + 16)) + sha256_a.subdata(in: 24 ..< (24 + 8)) + let aesIv = sha256_b.subdata(in: 0 ..< 8) + sha256_a.subdata(in: 8 ..< (8 + 16)) + sha256_b.subdata(in: 24 ..< (24 + 8)) + + guard let data = MTAesDecrypt(rawData, aesKey, aesIv), data.count > 4 else { + return nil + } + + var dataLength: Int32 = 0 + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&dataLength, bytes, 4) + } + + if dataLength < 0 || dataLength > data.count - 4 { + return nil + } + + let checkMsgKeyLarge = sha256Digest(key.data.subdata(in: (88 + x) ..< (88 + x + 32)) + data) + let checkMsgKey = checkMsgKeyLarge.subdata(in: 8 ..< (8 + 16)) + + if checkMsgKey != msgKey { + return nil + } + + return data.subdata(in: 4 ..< (4 + Int(dataLength))) +} + +public func decryptedNotificationPayload(account: Account, data: Data) -> Signal { + return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: true) + |> map { secret -> Data? in + return decryptedNotificationPayload(key: secret, data: data) + } +} + +public struct AccountBackupData: Codable, Equatable { + public var masterDatacenterId: Int32 + public var peerId: Int64 + public var masterDatacenterKey: Data + public var masterDatacenterKeyId: Int64 +} + +public final class AccountBackupDataAttribute: AccountRecordAttribute, Equatable { + public let data: AccountBackupData? + + public init(data: AccountBackupData?) { + self.data = data + } + + public init(decoder: PostboxDecoder) { + self.data = try? JSONDecoder().decode(AccountBackupData.self, from: decoder.decodeDataForKey("data") ?? Data()) + } + + public func encode(_ encoder: PostboxEncoder) { + if let data = self.data, let serializedData = try? JSONEncoder().encode(data) { + encoder.encodeData(serializedData, forKey: "data") + } + } + + public static func ==(lhs: AccountBackupDataAttribute, rhs: AccountBackupDataAttribute) -> Bool { + return lhs.data == rhs.data + } + + public func isEqual(to: AccountRecordAttribute) -> Bool { + if let to = to as? AccountBackupDataAttribute { + return self == to + } else { + return false + } + } +} + +public func accountBackupData(postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> AccountBackupData? in + guard let state = transaction.getState() as? AuthorizedAccountState else { + return nil + } + guard let authInfoData = transaction.keychainEntryForKey("persistent:datacenterAuthInfoById") else { + return nil + } + guard let authInfo = NSKeyedUnarchiver.unarchiveObject(with: authInfoData) as? NSDictionary else { + return nil + } + guard let datacenterAuthInfo = authInfo.object(forKey: state.masterDatacenterId as NSNumber) as? MTDatacenterAuthInfo else { + return nil + } + guard let authKey = datacenterAuthInfo.authKey else { + return nil + } + return AccountBackupData(masterDatacenterId: state.masterDatacenterId, peerId: state.peerId.toInt64(), masterDatacenterKey: authKey, masterDatacenterKeyId: datacenterAuthInfo.authKeyId) + } +} + +public class Account { + public let id: AccountRecordId + public let basePath: String + public let testingEnvironment: Bool + public let supplementary: Bool + public let postbox: Postbox + public let network: Network + public let networkArguments: NetworkInitializationArguments + public let peerId: PeerId + + public let auxiliaryMethods: AccountAuxiliaryMethods + + private let serviceQueue = Queue() + + public private(set) var stateManager: AccountStateManager! + private(set) var contactSyncManager: ContactSyncManager! + public private(set) var callSessionManager: CallSessionManager! + public private(set) var viewTracker: AccountViewTracker! + public private(set) var pendingMessageManager: PendingMessageManager! + public private(set) var messageMediaPreuploadManager: MessageMediaPreuploadManager! + private(set) var mediaReferenceRevalidationContext: MediaReferenceRevalidationContext! + private var peerInputActivityManager: PeerInputActivityManager! + private var localInputActivityManager: PeerInputActivityManager! + private var accountPresenceManager: AccountPresenceManager! + private var notificationAutolockReportManager: NotificationAutolockReportManager! + fileprivate let managedContactsDisposable = MetaDisposable() + fileprivate let managedStickerPacksDisposable = MetaDisposable() + private let becomeMasterDisposable = MetaDisposable() + private let managedServiceViewsDisposable = MetaDisposable() + private let managedOperationsDisposable = DisposableSet() + private var storageSettingsDisposable: Disposable? + + public let importableContacts = Promise<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData]>() + + public let shouldBeServiceTaskMaster = Promise() + public let shouldKeepOnlinePresence = Promise() + public let autolockReportDeadline = Promise() + public let shouldExplicitelyKeepWorkerConnections = Promise(false) + public let shouldKeepBackgroundDownloadConnections = Promise(false) + + private let networkStateValue = Promise(.waitingForNetwork) + public var networkState: Signal { + return self.networkStateValue.get() + } + + private let networkTypeValue = Promise() + public var networkType: Signal { + return self.networkTypeValue.get() + } + + private let _loggedOut = ValuePromise(false, ignoreRepeated: true) + public var loggedOut: Signal { + return self._loggedOut.get() + } + + private let _importantTasksRunning = ValuePromise([], ignoreRepeated: true) + public var importantTasksRunning: Signal { + return self._importantTasksRunning.get() + } + + fileprivate let masterNotificationKey = Atomic(value: nil) + + var transformOutgoingMessageMedia: TransformOutgoingMessageMedia? + + private var lastSmallLogPostTimestamp: Double? + private let smallLogPostDisposable = MetaDisposable() + + public init(accountManager: AccountManager, id: AccountRecordId, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, networkArguments: NetworkInitializationArguments, peerId: PeerId, auxiliaryMethods: AccountAuxiliaryMethods, supplementary: Bool) { + self.id = id + self.basePath = basePath + self.testingEnvironment = testingEnvironment + self.postbox = postbox + self.network = network + self.networkArguments = networkArguments + self.peerId = peerId + + self.auxiliaryMethods = auxiliaryMethods + self.supplementary = supplementary + + self.peerInputActivityManager = PeerInputActivityManager() + self.callSessionManager = CallSessionManager(postbox: postbox, network: network, maxLayer: networkArguments.voipMaxLayer, addUpdates: { [weak self] updates in + self?.stateManager?.addUpdates(updates) + }) + self.stateManager = AccountStateManager(accountPeerId: self.peerId, accountManager: accountManager, postbox: self.postbox, network: self.network, callSessionManager: self.callSessionManager, addIsContactUpdates: { [weak self] updates in + self?.contactSyncManager?.addIsContactUpdates(updates) + }, shouldKeepOnlinePresence: self.shouldKeepOnlinePresence.get(), peerInputActivityManager: self.peerInputActivityManager, auxiliaryMethods: auxiliaryMethods) + self.contactSyncManager = ContactSyncManager(postbox: postbox, network: network, accountPeerId: peerId, stateManager: self.stateManager) + self.localInputActivityManager = PeerInputActivityManager() + self.accountPresenceManager = AccountPresenceManager(shouldKeepOnlinePresence: self.shouldKeepOnlinePresence.get(), network: network) + let _ = (postbox.transaction { transaction -> Void in + transaction.updatePeerPresencesInternal(presences: [peerId: TelegramUserPresence(status: .present(until: Int32.max - 1), lastActivity: 0)], merge: { _, updated in return updated }) + transaction.setNeedsPeerGroupMessageStatsSynchronization(groupId: Namespaces.PeerGroup.archive, namespace: Namespaces.Message.Cloud) + }).start() + self.notificationAutolockReportManager = NotificationAutolockReportManager(deadline: self.autolockReportDeadline.get(), network: network) + self.autolockReportDeadline.set( + accountManager.accessChallengeData() + |> map { dataView -> Int32? in + guard let autolockDeadline = dataView.data.autolockDeadline else { + return nil + } + return autolockDeadline + } + |> distinctUntilChanged + ) + + self.viewTracker = AccountViewTracker(account: self) + self.messageMediaPreuploadManager = MessageMediaPreuploadManager() + self.mediaReferenceRevalidationContext = MediaReferenceRevalidationContext() + self.pendingMessageManager = PendingMessageManager(network: network, postbox: postbox, accountPeerId: peerId, auxiliaryMethods: auxiliaryMethods, stateManager: self.stateManager, localInputActivityManager: self.localInputActivityManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.mediaReferenceRevalidationContext) + + self.network.loggedOut = { [weak self] in + Logger.shared.log("Account", "network logged out") + if let strongSelf = self { + strongSelf._loggedOut.set(true) + strongSelf.callSessionManager.dropAll() + } + } + self.network.didReceiveSoftAuthResetError = { [weak self] in + self?.postSmallLogIfNeeded() + } + + let networkStateQueue = Queue() + /* + let previousNetworkStatus = Atomic(value: nil) + let delayNetworkStatus = self.shouldBeServiceTaskMaster.get() + |> map { mode -> Bool in + switch mode { + case .now, .always: + return true + case .never: + return false + } + } + |> distinctUntilChanged + |> deliverOn(networkStateQueue) + |> mapToSignal { value -> Signal in + var shouldDelay = false + let _ = previousNetworkStatus.modify { previous in + if let previous = previous { + if !previous && value { + shouldDelay = true + } + } else { + shouldDelay = true + } + return value + } + if shouldDelay { + let delayedFalse = Signal.single(false) + |> delay(3.0, queue: networkStateQueue) + return .single(true) + |> then(delayedFalse) + } else { + return .single(!value) + } + }*/ + let networkStateSignal = combineLatest(queue: networkStateQueue, self.stateManager.isUpdating, network.connectionStatus/*, delayNetworkStatus*/) + |> map { isUpdating, connectionStatus/*, delayNetworkStatus*/ -> AccountNetworkState in + /*if delayNetworkStatus { + return .online(proxy: nil) + }*/ + + switch connectionStatus { + case .waitingForNetwork: + return .waitingForNetwork + case let .connecting(proxyAddress, proxyHasConnectionIssues): + var proxyState: AccountNetworkProxyState? + if let proxyAddress = proxyAddress { + proxyState = AccountNetworkProxyState(address: proxyAddress, hasConnectionIssues: proxyHasConnectionIssues) + } + return .connecting(proxy: proxyState) + case let .updating(proxyAddress): + var proxyState: AccountNetworkProxyState? + if let proxyAddress = proxyAddress { + proxyState = AccountNetworkProxyState(address: proxyAddress, hasConnectionIssues: false) + } + return .updating(proxy: proxyState) + case let .online(proxyAddress): + var proxyState: AccountNetworkProxyState? + if let proxyAddress = proxyAddress { + proxyState = AccountNetworkProxyState(address: proxyAddress, hasConnectionIssues: false) + } + + if isUpdating { + return .updating(proxy: proxyState) + } else { + return .online(proxy: proxyState) + } + } + } + self.networkStateValue.set(networkStateSignal + |> distinctUntilChanged) + + self.networkTypeValue.set(currentNetworkType()) + + let serviceTasksMasterBecomeMaster = shouldBeServiceTaskMaster.get() + |> distinctUntilChanged + |> deliverOn(self.serviceQueue) + + self.becomeMasterDisposable.set(serviceTasksMasterBecomeMaster.start(next: { [weak self] value in + if let strongSelf = self, (value == .now || value == .always) { + strongSelf.postbox.becomeMasterClient() + } + })) + + let shouldBeMaster = combineLatest(shouldBeServiceTaskMaster.get(), postbox.isMasterClient()) + |> map { [weak self] shouldBeMaster, isMaster -> Bool in + if shouldBeMaster == .always && !isMaster { + self?.postbox.becomeMasterClient() + } + return (shouldBeMaster == .now || shouldBeMaster == .always) && isMaster + } + |> distinctUntilChanged + + self.network.shouldKeepConnection.set(shouldBeMaster) + self.network.shouldExplicitelyKeepWorkerConnections.set(self.shouldExplicitelyKeepWorkerConnections.get()) + self.network.shouldKeepBackgroundDownloadConnections.set(self.shouldKeepBackgroundDownloadConnections.get()) + + let serviceTasksMaster = shouldBeMaster + |> deliverOn(self.serviceQueue) + |> mapToSignal { [weak self] value -> Signal in + if let strongSelf = self, value { + Logger.shared.log("Account", "Became master") + return managedServiceViews(accountPeerId: peerId, network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, pendingMessageManager: strongSelf.pendingMessageManager) + } else { + Logger.shared.log("Account", "Resigned master") + return .never() + } + } + self.managedServiceViewsDisposable.set(serviceTasksMaster.start()) + + let pendingMessageManager = self.pendingMessageManager + self.managedOperationsDisposable.add(postbox.unsentMessageIdsView().start(next: { [weak pendingMessageManager] view in + pendingMessageManager?.updatePendingMessageIds(view.ids) + })) + + self.managedOperationsDisposable.add(managedSecretChatOutgoingOperations(auxiliaryMethods: auxiliaryMethods, postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedCloudChatRemoveMessagesOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedAutoremoveMessageOperations(postbox: self.postbox).start()) + self.managedOperationsDisposable.add(managedGlobalNotificationSettings(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedSynchronizePinnedChatsOperations(postbox: self.postbox, network: self.network, accountPeerId: self.peerId, stateManager: self.stateManager).start()) + + self.managedOperationsDisposable.add(managedSynchronizeGroupedPeersOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .stickers).start()) + self.managedOperationsDisposable.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager, namespace: .masks).start()) + self.managedOperationsDisposable.add(managedSynchronizeMarkFeaturedStickerPacksAsSeenOperations(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedSynchronizeRecentlyUsedMediaOperations(postbox: self.postbox, network: self.network, category: .stickers, revalidationContext: self.mediaReferenceRevalidationContext).start()) + self.managedOperationsDisposable.add(managedSynchronizeSavedGifsOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) + self.managedOperationsDisposable.add(managedSynchronizeSavedStickersOperations(postbox: self.postbox, network: self.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) + self.managedOperationsDisposable.add(managedRecentlyUsedInlineBots(postbox: self.postbox, network: self.network, accountPeerId: peerId).start()) + self.managedOperationsDisposable.add(managedLocalTypingActivities(activities: self.localInputActivityManager.allActivities(), postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start()) + self.managedOperationsDisposable.add(managedSynchronizeConsumeMessageContentOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedConsumePersonalMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start()) + + let importantBackgroundOperations: [Signal] = [ + managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] }, + self.pendingMessageManager.hasPendingMessages |> map { $0 ? AccountRunningImportantTasks.pendingMessages : [] }, + self.accountPresenceManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }, + self.notificationAutolockReportManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] } + ] + let importantBackgroundOperationsRunning = combineLatest(queue: Queue(), importantBackgroundOperations) + |> map { values -> AccountRunningImportantTasks in + var result: AccountRunningImportantTasks = [] + for value in values { + result.formUnion(value) + } + return result + } + + self.managedOperationsDisposable.add(importantBackgroundOperationsRunning.start(next: { [weak self] value in + if let strongSelf = self { + strongSelf._importantTasksRunning.set(value) + } + })) + self.managedOperationsDisposable.add((accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) + |> map { sharedData -> ProxyServerSettings? in + if let settings = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + return settings.effectiveActiveServer + } else { + return nil + } + } + |> distinctUntilChanged).start(next: { activeServer in + let updated = activeServer.flatMap { activeServer -> MTSocksProxySettings? in + return activeServer.mtProxySettings + } + network.context.updateApiEnvironment { environment in + let current = environment?.socksProxySettings + let updateNetwork: Bool + if let current = current, let updated = updated { + updateNetwork = !current.isEqual(updated) + } else { + updateNetwork = (current != nil) != (updated != nil) + } + if updateNetwork { + network.dropConnectionStatus() + return environment?.withUpdatedSocksProxySettings(updated) + } else { + return nil + } + } + })) + self.managedOperationsDisposable.add(managedConfigurationUpdates(accountManager: accountManager, postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedVoipConfigurationUpdates(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedAppConfigurationUpdates(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedAutodownloadSettingsUpdates(accountManager: accountManager, network: self.network).start()) + self.managedOperationsDisposable.add(managedTermsOfServiceUpdates(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedAppChangelog(postbox: self.postbox, network: self.network, stateManager: self.stateManager, appVersion: self.networkArguments.appVersion).start()) + self.managedOperationsDisposable.add(managedProxyInfoUpdates(postbox: self.postbox, network: self.network, viewTracker: self.viewTracker).start()) + self.managedOperationsDisposable.add(managedLocalizationUpdatesOperations(accountManager: accountManager, postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedPendingPeerNotificationSettings(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedSynchronizeAppLogEventsOperations(postbox: self.postbox, network: self.network).start()) + + self.managedOperationsDisposable.add(managedNotificationSettingsBehaviors(postbox: self.postbox).start()) + + let mediaBox = postbox.mediaBox + self.storageSettingsDisposable = accountManager.sharedData(keys: [SharedDataKeys.cacheStorageSettings]).start(next: { [weak mediaBox] sharedData in + guard let mediaBox = mediaBox else { + return + } + let settings: CacheStorageSettings = sharedData.entries[SharedDataKeys.cacheStorageSettings] as? CacheStorageSettings ?? CacheStorageSettings.defaultSettings + mediaBox.setMaxStoreTime(settings.defaultCacheStorageTimeout) + }) + + let _ = masterNotificationsKey(masterNotificationKeyValue: self.masterNotificationKey, postbox: self.postbox, ignoreDisabled: false).start(next: { key in + let encoder = JSONEncoder() + if let data = try? encoder.encode(key) { + let _ = try? data.write(to: URL(fileURLWithPath: "\(basePath)/notificationsKey")) + } + }) + } + + deinit { + self.managedContactsDisposable.dispose() + self.managedStickerPacksDisposable.dispose() + self.managedServiceViewsDisposable.dispose() + self.managedOperationsDisposable.dispose() + self.storageSettingsDisposable?.dispose() + self.smallLogPostDisposable.dispose() + } + + private func postSmallLogIfNeeded() { + let timestamp = CFAbsoluteTimeGetCurrent() + if self.lastSmallLogPostTimestamp == nil || self.lastSmallLogPostTimestamp! < timestamp - 30.0 { + self.lastSmallLogPostTimestamp = timestamp + let network = self.network + + self.smallLogPostDisposable.set((Logger.shared.collectShortLog() + |> mapToSignal { events -> Signal in + if events.isEmpty { + return .complete() + } else { + return network.request(Api.functions.help.saveAppLog(events: events.map { event -> Api.InputAppEvent in + return .inputAppEvent(time: event.0, type: "", peer: 0, data: .jsonString(value: event.1)) + })) + |> ignoreValues + |> `catch` { _ -> Signal in + return .complete() + } + } + }).start()) + } + } + + public func resetStateManagement() { + self.stateManager.reset() + self.restartContactManagement() + self.managedStickerPacksDisposable.set(manageStickerPacks(network: self.network, postbox: self.postbox).start()) + if !self.supplementary { + self.viewTracker.chatHistoryPreloadManager.start() + } + } + + public func resetCachedData() { + self.viewTracker.reset() + } + + public func restartContactManagement() { + self.contactSyncManager.beginSync(importableContacts: self.importableContacts.get()) + } + + public func addAdditionalPreloadHistoryPeerId(peerId: PeerId) -> Disposable { + return self.viewTracker.chatHistoryPreloadManager.addAdditionalPeerId(peerId: peerId) + } + + public func peerInputActivities(peerId: PeerId) -> Signal<[(PeerId, PeerInputActivity)], NoError> { + return self.peerInputActivityManager.activities(peerId: peerId) + |> map { activities in + return activities.map({ ($0.0, $0.1.activity) }) + } + } + + public func allPeerInputActivities() -> Signal<[PeerId: [PeerId: PeerInputActivity]], NoError> { + return self.peerInputActivityManager.allActivities() + |> map { activities in + var result: [PeerId: [PeerId: PeerInputActivity]] = [:] + for (chatPeerId, chatActivities) in activities { + result[chatPeerId] = chatActivities.mapValues({ $0.activity }) + } + return result + } + } + + public func updateLocalInputActivity(peerId: PeerId, activity: PeerInputActivity, isPresent: Bool) { + self.localInputActivityManager.transaction { manager in + if isPresent { + manager.addActivity(chatPeerId: peerId, peerId: self.peerId, activity: activity) + } else { + manager.removeActivity(chatPeerId: peerId, peerId: self.peerId, activity: activity) + } + } + } + + public func acquireLocalInputActivity(peerId: PeerId, activity: PeerInputActivity) -> Disposable { + return self.localInputActivityManager.acquireActivity(chatPeerId: peerId, peerId: self.peerId, activity: activity) + } +} + +public func accountNetworkUsageStats(account: Account, reset: ResetNetworkUsageStats) -> Signal { + return networkUsageStats(basePath: account.basePath, reset: reset) +} + +public func updateAccountNetworkUsageStats(account: Account, category: MediaResourceStatsCategory, delta: NetworkUsageStatsConnectionsEntry) { + updateNetworkUsageStats(basePath: account.basePath, category: category, delta: delta) +} + +public typealias FetchCachedResourceRepresentation = (_ account: Account, _ resource: MediaResource, _ representation: CachedMediaResourceRepresentation) -> Signal +public typealias TransformOutgoingMessageMedia = (_ postbox: Postbox, _ network: Network, _ media: AnyMediaReference, _ userInteractive: Bool) -> Signal + +public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: FetchCachedResourceRepresentation? = nil, transformOutgoingMessageMedia: TransformOutgoingMessageMedia? = nil, preFetchedResourcePath: @escaping (MediaResource) -> String? = { _ in return nil }) { + account.postbox.mediaBox.preFetchedResourcePath = preFetchedResourcePath + account.postbox.mediaBox.fetchResource = { [weak account] resource, intervals, parameters -> Signal in + if let strongAccount = account { + if let result = fetchResource(account: strongAccount, resource: resource, intervals: intervals, parameters: parameters) { + return result + } else if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount, resource, intervals, parameters) { + return result + } else { + return .never() + } + } else { + return .never() + } + } + + account.postbox.mediaBox.fetchCachedResourceRepresentation = { [weak account] resource, representation in + if let strongAccount = account, let fetchCachedResourceRepresentation = fetchCachedResourceRepresentation { + return fetchCachedResourceRepresentation(strongAccount, resource, representation) + } else { + return .never() + } + } + + account.transformOutgoingMessageMedia = transformOutgoingMessageMedia + account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia +} diff --git a/submodules/TelegramCore/TelegramCore/AccountEnvironmentAttribute.swift b/submodules/TelegramCore/TelegramCore/AccountEnvironmentAttribute.swift new file mode 100644 index 0000000000..e850b9d881 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountEnvironmentAttribute.swift @@ -0,0 +1,37 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public enum AccountEnvironment: Int32 { + case production = 0 + case test = 1 +} + +public final class AccountEnvironmentAttribute: AccountRecordAttribute { + public let environment: AccountEnvironment + + public init(environment: AccountEnvironment) { + self.environment = environment + } + + public init(decoder: PostboxDecoder) { + self.environment = AccountEnvironment(rawValue: decoder.decodeInt32ForKey("environment", orElse: 0)) ?? .production + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.environment.rawValue, forKey: "environment") + } + + public func isEqual(to: AccountRecordAttribute) -> Bool { + guard let to = to as? AccountEnvironmentAttribute else { + return false + } + if self.environment != to.environment { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountIntermediateState.swift b/submodules/TelegramCore/TelegramCore/AccountIntermediateState.swift new file mode 100644 index 0000000000..b3763b19cb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountIntermediateState.swift @@ -0,0 +1,553 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +struct PeerChatInfo { + var notificationSettings: PeerNotificationSettings +} + +final class AccountInitialState { + let state: AuthorizedAccountState.State + let peerIds: Set + let chatStates: [PeerId: PeerChatState] + let peerChatInfos: [PeerId: PeerChatInfo] + let peerIdsRequiringLocalChatState: Set + let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]] + let cloudReadStates: [PeerId: PeerReadState] + let channelsToPollExplicitely: Set + + init(state: AuthorizedAccountState.State, peerIds: Set, peerIdsRequiringLocalChatState: Set, chatStates: [PeerId: PeerChatState], peerChatInfos: [PeerId: PeerChatInfo], locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]], cloudReadStates: [PeerId: PeerReadState], channelsToPollExplicitely: Set) { + self.state = state + self.peerIds = peerIds + self.chatStates = chatStates + self.peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatState + self.peerChatInfos = peerChatInfos + self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps + self.cloudReadStates = cloudReadStates + self.channelsToPollExplicitely = channelsToPollExplicitely + } +} + +enum AccountStateUpdatePinnedItemIdsOperation { + case pin(PinnedItemId) + case unpin(PinnedItemId) + case reorder([PinnedItemId]) + case sync +} + +enum AccountStateUpdateStickerPacksOperation { + case add(Api.messages.StickerSet) + case reorder(SynchronizeInstalledStickerPacksOperationNamespace, [Int64]) + case sync +} + +enum AccountStateNotificationSettingsSubject { + case peer(PeerId) +} + +enum AccountStateGlobalNotificationSettingsSubject { + case privateChats + case groups + case channels +} + +enum AccountStateMutationOperation { + case AddMessages([StoreMessage], AddMessagesLocation) + case DeleteMessagesWithGlobalIds([Int32]) + case DeleteMessages([MessageId]) + case EditMessage(MessageId, StoreMessage) + case UpdateMessagePoll(MediaId, Api.Poll?, Api.PollResults) + case UpdateMedia(MediaId, Media?) + case ReadInbox(MessageId) + case ReadOutbox(MessageId, Int32?) + case ResetReadState(peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32, markedUnread: Bool?) + case ResetIncomingReadState(groupId: PeerGroupId, peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, count: Int32, pts: Int32) + case UpdatePeerChatUnreadMark(PeerId, MessageId.Namespace, Bool) + case ResetMessageTagSummary(PeerId, MessageId.Namespace, Int32, MessageHistoryTagNamespaceCountValidityRange) + case ReadGroupFeedInbox(PeerGroupId, MessageIndex) + case UpdateState(AuthorizedAccountState.State) + case UpdateChannelState(PeerId, ChannelState) + case UpdateNotificationSettings(AccountStateNotificationSettingsSubject, PeerNotificationSettings) + case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings) + case MergeApiChats([Api.Chat]) + case UpdatePeer(PeerId, (Peer?) -> Peer?) + case UpdateIsContact(PeerId, Bool) + case UpdateCachedPeerData(PeerId, (CachedPeerData?) -> CachedPeerData?) + case MergeApiUsers([Api.User]) + case MergePeerPresences([PeerId: Api.UserStatus], Bool) + case UpdateSecretChat(chat: Api.EncryptedChat, timestamp: Int32) + case AddSecretMessages([Api.EncryptedMessage]) + case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32) + case AddPeerInputActivity(chatPeerId: PeerId, peerId: PeerId?, activity: PeerInputActivity?) + case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation) + case ReadMessageContents((PeerId?, [Int32])) + case UpdateMessageImpressionCount(MessageId, Int32) + case UpdateInstalledStickerPacks(AccountStateUpdateStickerPacksOperation) + case UpdateRecentGifs + case UpdateChatInputState(PeerId, SynchronizeableChatInputState?) + case UpdateCall(Api.PhoneCall) + case UpdateLangPack(String, Api.LangPackDifference?) + case UpdateMinAvailableMessage(MessageId) + case UpdatePeerChatInclusion(peerId: PeerId, groupId: PeerGroupId, changedGroup: Bool) + case UpdatePeersNearby([PeerNearby]) +} + +struct AccountMutableState { + let initialState: AccountInitialState + let branchOperationIndex: Int + + var operations: [AccountStateMutationOperation] = [] + + var state: AuthorizedAccountState.State + var peers: [PeerId: Peer] + var chatStates: [PeerId: PeerChatState] + var peerChatInfos: [PeerId: PeerChatInfo] + var referencedMessageIds: Set + var storedMessages: Set + var readInboxMaxIds: [PeerId: MessageId] + var namespacesWithHolesFromPreviousState: [PeerId: Set] + + var storedMessagesByPeerIdAndTimestamp: [PeerId: Set] + var displayAlerts: [(text: String, isDropAuth: Bool)] = [] + + var insertedPeers: [PeerId: Peer] = [:] + + var preCachedResources: [(MediaResource, Data)] = [] + + var updatedMaxMessageId: Int32? + var updatedQts: Int32? + + var externallyUpdatedPeerId = Set() + + init(initialState: AccountInitialState, initialPeers: [PeerId: Peer], initialReferencedMessageIds: Set, initialStoredMessages: Set, initialReadInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set]) { + self.initialState = initialState + self.state = initialState.state + self.peers = initialPeers + self.referencedMessageIds = initialReferencedMessageIds + self.storedMessages = initialStoredMessages + self.readInboxMaxIds = initialReadInboxMaxIds + self.chatStates = initialState.chatStates + self.peerChatInfos = initialState.peerChatInfos + self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp + self.branchOperationIndex = 0 + self.namespacesWithHolesFromPreviousState = [:] + } + + init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], chatStates: [PeerId: PeerChatState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set, storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: Set], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) { + self.initialState = initialState + self.operations = operations + self.state = state + self.peers = peers + self.chatStates = chatStates + self.referencedMessageIds = referencedMessageIds + self.storedMessages = storedMessages + self.peerChatInfos = peerChatInfos + self.readInboxMaxIds = readInboxMaxIds + self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp + self.namespacesWithHolesFromPreviousState = namespacesWithHolesFromPreviousState + self.displayAlerts = displayAlerts + self.branchOperationIndex = branchOperationIndex + } + + func branch() -> AccountMutableState { + return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, chatStates: self.chatStates, peerChatInfos: self.peerChatInfos, referencedMessageIds: self.referencedMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, displayAlerts: self.displayAlerts, branchOperationIndex: self.operations.count) + } + + mutating func merge(_ other: AccountMutableState) { + self.referencedMessageIds.formUnion(other.referencedMessageIds) + for i in other.branchOperationIndex ..< other.operations.count { + self.addOperation(other.operations[i]) + } + for (_, peer) in other.insertedPeers { + self.peers[peer.id] = peer + } + self.preCachedResources.append(contentsOf: other.preCachedResources) + self.externallyUpdatedPeerId.formUnion(other.externallyUpdatedPeerId) + for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState { + if self.namespacesWithHolesFromPreviousState[peerId] == nil { + self.namespacesWithHolesFromPreviousState[peerId] = Set() + } + for namespace in namespaces { + self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace) + } + } + self.displayAlerts.append(contentsOf: other.displayAlerts) + } + + mutating func addPreCachedResource(_ resource: MediaResource, data: Data) { + self.preCachedResources.append((resource, data)) + } + + mutating func addExternallyUpdatedPeerId(_ peerId: PeerId) { + self.externallyUpdatedPeerId.insert(peerId) + } + + mutating func addMessages(_ messages: [StoreMessage], location: AddMessagesLocation) { + self.addOperation(.AddMessages(messages, location)) + } + + mutating func addDisplayAlert(_ text: String, isDropAuth: Bool) { + self.displayAlerts.append((text: text, isDropAuth: isDropAuth)) + } + + mutating func deleteMessagesWithGlobalIds(_ globalIds: [Int32]) { + self.addOperation(.DeleteMessagesWithGlobalIds(globalIds)) + } + + mutating func deleteMessages(_ messageIds: [MessageId]) { + self.addOperation(.DeleteMessages(messageIds)) + } + + mutating func editMessage(_ id: MessageId, message: StoreMessage) { + self.addOperation(.EditMessage(id, message)) + } + + mutating func updateMessagePoll(_ id: MediaId, poll: Api.Poll?, results: Api.PollResults) { + self.addOperation(.UpdateMessagePoll(id, poll, results)) + } + + mutating func updateMedia(_ id: MediaId, media: Media?) { + self.addOperation(.UpdateMedia(id, media)) + } + + mutating func readInbox(_ messageId: MessageId) { + self.addOperation(.ReadInbox(messageId)) + } + + mutating func readOutbox(_ messageId: MessageId, timestamp: Int32?) { + self.addOperation(.ReadOutbox(messageId, timestamp)) + } + + mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) { + self.addOperation(.ReadGroupFeedInbox(groupId, index)) + } + + mutating func resetReadState(_ peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32, markedUnread: Bool?) { + self.addOperation(.ResetReadState(peerId: peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread)) + } + + mutating func resetIncomingReadState(groupId: PeerGroupId, peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, count: Int32, pts: Int32) { + self.addOperation(.ResetIncomingReadState(groupId: groupId, peerId: peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, count: count, pts: pts)) + } + + mutating func updatePeerChatUnreadMark(_ peerId: PeerId, namespace: MessageId.Namespace, value: Bool) { + self.addOperation(.UpdatePeerChatUnreadMark(peerId, namespace, value)) + } + + mutating func resetMessageTagSummary(_ peerId: PeerId, namespace: MessageId.Namespace, count: Int32, range: MessageHistoryTagNamespaceCountValidityRange) { + self.addOperation(.ResetMessageTagSummary(peerId, namespace, count, range)) + } + + mutating func updateState(_ state: AuthorizedAccountState.State) { + if self.initialState.state.seq != state.qts { + self.updatedQts = state.qts + } + self.addOperation(.UpdateState(state)) + } + + mutating func updateChannelState(_ peerId: PeerId, state: ChannelState) { + self.addOperation(.UpdateChannelState(peerId, state)) + } + + mutating func updateNotificationSettings(_ subject: AccountStateNotificationSettingsSubject, notificationSettings: PeerNotificationSettings) { + self.addOperation(.UpdateNotificationSettings(subject, notificationSettings)) + } + + mutating func updateGlobalNotificationSettings(_ subject: AccountStateGlobalNotificationSettingsSubject, notificationSettings: MessageNotificationSettings) { + self.addOperation(.UpdateGlobalNotificationSettings(subject, notificationSettings)) + } + + mutating func setNeedsHoleFromPreviousState(peerId: PeerId, namespace: MessageId.Namespace) { + if self.namespacesWithHolesFromPreviousState[peerId] == nil { + self.namespacesWithHolesFromPreviousState[peerId] = Set() + } + self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace) + } + + mutating func mergeChats(_ chats: [Api.Chat]) { + self.addOperation(.MergeApiChats(chats)) + } + + mutating func updatePeer(_ id: PeerId, _ f: @escaping (Peer?) -> Peer?) { + self.addOperation(.UpdatePeer(id, f)) + } + + mutating func updatePeerIsContact(_ id: PeerId, isContact: Bool) { + self.addOperation(.UpdateIsContact(id, isContact)) + } + + mutating func updateCachedPeerData(_ id: PeerId, _ f: @escaping (CachedPeerData?) -> CachedPeerData?) { + self.addOperation(.UpdateCachedPeerData(id, f)) + } + + mutating func updateLangPack(langCode: String, difference: Api.LangPackDifference?) { + self.addOperation(.UpdateLangPack(langCode, difference)) + } + + mutating func updateMinAvailableMessage(_ id: MessageId) { + self.addOperation(.UpdateMinAvailableMessage(id)) + } + + mutating func updatePeerChatInclusion(peerId: PeerId, groupId: PeerGroupId, changedGroup: Bool) { + self.addOperation(.UpdatePeerChatInclusion(peerId: peerId, groupId: groupId, changedGroup: changedGroup)) + } + + mutating func updatePeersNearby(_ peersNearby: [PeerNearby]) { + self.addOperation(.UpdatePeersNearby(peersNearby)) + } + + mutating func mergeUsers(_ users: [Api.User]) { + self.addOperation(.MergeApiUsers(users)) + + var presences: [PeerId: Api.UserStatus] = [:] + for user in users { + switch user { + case let .user(_, id, _, _, _, _, _, _, status, _, _, _, _): + if let status = status { + presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] = status + } + break + case .userEmpty: + break + } + } + if !presences.isEmpty { + self.addOperation(.MergePeerPresences(presences, false)) + } + } + + mutating func mergePeerPresences(_ presences: [PeerId: Api.UserStatus], explicit: Bool) { + self.addOperation(.MergePeerPresences(presences, explicit)) + } + + mutating func updateSecretChat(chat: Api.EncryptedChat, timestamp: Int32) { + self.addOperation(.UpdateSecretChat(chat: chat, timestamp: timestamp)) + } + + mutating func addSecretMessages(_ messages: [Api.EncryptedMessage]) { + self.addOperation(.AddSecretMessages(messages)) + } + + mutating func readSecretOutbox(peerId: PeerId, timestamp: Int32, actionTimestamp: Int32) { + self.addOperation(.ReadSecretOutbox(peerId: peerId, maxTimestamp: timestamp, actionTimestamp: actionTimestamp)) + } + + mutating func addPeerInputActivity(chatPeerId: PeerId, peerId: PeerId?, activity: PeerInputActivity?) { + self.addOperation(.AddPeerInputActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity)) + } + + mutating func addUpdatePinnedItemIds(groupId: PeerGroupId, operation: AccountStateUpdatePinnedItemIdsOperation) { + self.addOperation(.UpdatePinnedItemIds(groupId, operation)) + } + + mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32])) { + self.addOperation(.ReadMessageContents(peerIdsAndMessageIds)) + } + + mutating func addUpdateMessageImpressionCount(id: MessageId, count: Int32) { + self.addOperation(.UpdateMessageImpressionCount(id, count)) + } + + mutating func addUpdateInstalledStickerPacks(_ operation: AccountStateUpdateStickerPacksOperation) { + self.addOperation(.UpdateInstalledStickerPacks(operation)) + } + + mutating func addUpdateRecentGifs() { + self.addOperation(.UpdateRecentGifs) + } + + mutating func addUpdateChatInputState(peerId: PeerId, state: SynchronizeableChatInputState?) { + self.addOperation(.UpdateChatInputState(peerId, state)) + } + + mutating func addUpdateCall(_ call: Api.PhoneCall) { + self.addOperation(.UpdateCall(call)) + } + + mutating func addOperation(_ operation: AccountStateMutationOperation) { + switch operation { + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby: + break + case let .AddMessages(messages, location): + for message in messages { + if case let .Id(id) = message.id { + self.storedMessages.insert(id) + if case .UpperHistoryBlock = location { + if (id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup) && id.namespace == Namespaces.Message.Cloud { + if let updatedMaxMessageId = self.updatedMaxMessageId { + if updatedMaxMessageId < id.id { + self.updatedMaxMessageId = id.id + } + } else { + self.updatedMaxMessageId = id.id + } + } + } + } + inner: for attribute in message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + self.referencedMessageIds.insert(attribute.messageId) + break inner + } + } + + } + case let .UpdateState(state): + self.state = state + case let .UpdateChannelState(peerId, channelState): + self.chatStates[peerId] = channelState + case let .UpdateNotificationSettings(subject, notificationSettings): + if case let .peer(peerId) = subject { + if var currentInfo = self.peerChatInfos[peerId] { + currentInfo.notificationSettings = notificationSettings + self.peerChatInfos[peerId] = currentInfo + } + } + case .UpdateGlobalNotificationSettings: + break + case let .MergeApiChats(chats): + for chat in chats { + if let groupOrChannel = mergeGroupOrChannel(lhs: peers[chat.peerId], rhs: chat) { + peers[groupOrChannel.id] = groupOrChannel + insertedPeers[groupOrChannel.id] = groupOrChannel + } + } + case let .MergeApiUsers(users): + for apiUser in users { + if let user = TelegramUser.merge(peers[apiUser.peerId] as? TelegramUser, rhs: apiUser) { + peers[user.id] = user + insertedPeers[user.id] = user + } + } + case let .UpdatePeer(id, f): + let peer = self.peers[id] + if let updatedPeer = f(peer) { + peers[id] = updatedPeer + insertedPeers[id] = updatedPeer + } + case let .ReadInbox(messageId): + let current = self.readInboxMaxIds[messageId.peerId] + if current == nil || current! < messageId { + self.readInboxMaxIds[messageId.peerId] = messageId + } + case let .ResetReadState(peerId, namespace, maxIncomingReadId, _, _, _, _): + let current = self.readInboxMaxIds[peerId] + if namespace == Namespaces.Message.Cloud { + if current == nil || current!.id < maxIncomingReadId { + self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId) + } + } + case let .ResetIncomingReadState(_, peerId, namespace, maxIncomingReadId, _, _): + let current = self.readInboxMaxIds[peerId] + if namespace == Namespaces.Message.Cloud { + if current == nil || current!.id < maxIncomingReadId { + self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId) + } + } + case let .ResetMessageTagSummary(peerId, namespace, count, range): + break + } + + self.operations.append(operation) + } +} + +struct AccountFinalState { + let state: AccountMutableState + let shouldPoll: Bool + let incomplete: Bool +} + +struct AccountReplayedFinalState { + let state: AccountFinalState + let addedIncomingMessageIds: [MessageId] + let addedSecretMessageIds: [MessageId] + let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] + let updatedWebpages: [MediaId: TelegramMediaWebpage] + let updatedCalls: [Api.PhoneCall] + let updatedPeersNearby: [PeerNearby]? + let isContactUpdates: [(PeerId, Bool)] + let delayNotificatonsUntil: Int32? +} + +struct AccountFinalStateEvents { + let addedIncomingMessageIds: [MessageId] + let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] + let updatedWebpages: [MediaId: TelegramMediaWebpage] + let updatedCalls: [Api.PhoneCall] + let updatedPeersNearby: [PeerNearby]? + let isContactUpdates: [(PeerId, Bool)] + let displayAlerts: [(text: String, isDropAuth: Bool)] + let delayNotificatonsUntil: Int32? + let updatedMaxMessageId: Int32? + let updatedQts: Int32? + let externallyUpdatedPeerId: Set + + var isEmpty: Bool { + return self.addedIncomingMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty + } + + init(addedIncomingMessageIds: [MessageId] = [], updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set()) { + self.addedIncomingMessageIds = addedIncomingMessageIds + self.updatedTypingActivities = updatedTypingActivities + self.updatedWebpages = updatedWebpages + self.updatedCalls = updatedCalls + self.updatedPeersNearby = updatedPeersNearby + self.isContactUpdates = isContactUpdates + self.displayAlerts = displayAlerts + self.delayNotificatonsUntil = delayNotificatonsUntil + self.updatedMaxMessageId = updatedMaxMessageId + self.updatedQts = updatedQts + self.externallyUpdatedPeerId = externallyUpdatedPeerId + } + + init(state: AccountReplayedFinalState) { + self.addedIncomingMessageIds = state.addedIncomingMessageIds + self.updatedTypingActivities = state.updatedTypingActivities + self.updatedWebpages = state.updatedWebpages + self.updatedCalls = state.updatedCalls + self.updatedPeersNearby = state.updatedPeersNearby + self.isContactUpdates = state.isContactUpdates + self.displayAlerts = state.state.state.displayAlerts + self.delayNotificatonsUntil = state.delayNotificatonsUntil + self.updatedMaxMessageId = state.state.state.updatedMaxMessageId + self.updatedQts = state.state.state.updatedQts + self.externallyUpdatedPeerId = state.state.state.externallyUpdatedPeerId + } + + func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents { + var delayNotificatonsUntil = self.delayNotificatonsUntil + if let other = self.delayNotificatonsUntil { + if delayNotificatonsUntil == nil || other > delayNotificatonsUntil! { + delayNotificatonsUntil = other + } + } + var updatedMaxMessageId: Int32? + var updatedQts: Int32? + if let lhsMaxMessageId = self.updatedMaxMessageId, let rhsMaxMessageId = other.updatedMaxMessageId { + updatedMaxMessageId = max(lhsMaxMessageId, rhsMaxMessageId) + } else { + updatedMaxMessageId = self.updatedMaxMessageId ?? other.updatedMaxMessageId + } + if let lhsQts = self.updatedQts, let rhsQts = other.updatedQts { + updatedQts = max(lhsQts, rhsQts) + } else { + updatedQts = self.updatedQts ?? other.updatedQts + } + + let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId) + + return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId) + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountManager.swift b/submodules/TelegramCore/TelegramCore/AccountManager.swift new file mode 100644 index 0000000000..4a7cc189d5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountManager.swift @@ -0,0 +1,418 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private enum AccountKind { + case authorized + case unauthorized +} + +private var declaredEncodables: Void = { + declareEncodable(AuthAccountRecord.self, f: { AuthAccountRecord(decoder: $0) }) + declareEncodable(UnauthorizedAccountState.self, f: { UnauthorizedAccountState(decoder: $0) }) + declareEncodable(AuthorizedAccountState.self, f: { AuthorizedAccountState(decoder: $0) }) + declareEncodable(TelegramUser.self, f: { TelegramUser(decoder: $0) }) + declareEncodable(TelegramGroup.self, f: { TelegramGroup(decoder: $0) }) + declareEncodable(TelegramChannel.self, f: { TelegramChannel(decoder: $0) }) + declareEncodable(TelegramMediaImage.self, f: { TelegramMediaImage(decoder: $0) }) + declareEncodable(TelegramMediaImageRepresentation.self, f: { TelegramMediaImageRepresentation(decoder: $0) }) + declareEncodable(TelegramMediaContact.self, f: { TelegramMediaContact(decoder: $0) }) + declareEncodable(TelegramMediaMap.self, f: { TelegramMediaMap(decoder: $0) }) + declareEncodable(TelegramMediaFile.self, f: { TelegramMediaFile(decoder: $0) }) + declareEncodable(TelegramMediaFileAttribute.self, f: { TelegramMediaFileAttribute(decoder: $0) }) + declareEncodable(CloudFileMediaResource.self, f: { CloudFileMediaResource(decoder: $0) }) + declareEncodable(ChannelState.self, f: { ChannelState(decoder: $0) }) + declareEncodable(RegularChatState.self, f: { RegularChatState(decoder: $0) }) + declareEncodable(InlineBotMessageAttribute.self, f: { InlineBotMessageAttribute(decoder: $0) }) + declareEncodable(TextEntitiesMessageAttribute.self, f: { TextEntitiesMessageAttribute(decoder: $0) }) + declareEncodable(ReplyMessageAttribute.self, f: { ReplyMessageAttribute(decoder: $0) }) + declareEncodable(CloudDocumentMediaResource.self, f: { CloudDocumentMediaResource(decoder: $0) }) + declareEncodable(TelegramMediaWebpage.self, f: { TelegramMediaWebpage(decoder: $0) }) + declareEncodable(ViewCountMessageAttribute.self, f: { ViewCountMessageAttribute(decoder: $0) }) + declareEncodable(NotificationInfoMessageAttribute.self, f: { NotificationInfoMessageAttribute(decoder: $0) }) + declareEncodable(TelegramMediaAction.self, f: { TelegramMediaAction(decoder: $0) }) + declareEncodable(TelegramPeerNotificationSettings.self, f: { TelegramPeerNotificationSettings(decoder: $0) }) + declareEncodable(CachedUserData.self, f: { CachedUserData(decoder: $0) }) + declareEncodable(BotInfo.self, f: { BotInfo(decoder: $0) }) + declareEncodable(CachedGroupData.self, f: { CachedGroupData(decoder: $0) }) + declareEncodable(CachedChannelData.self, f: { CachedChannelData(decoder: $0) }) + declareEncodable(TelegramUserPresence.self, f: { TelegramUserPresence(decoder: $0) }) + declareEncodable(LocalFileMediaResource.self, f: { LocalFileMediaResource(decoder: $0) }) + declareEncodable(StickerPackCollectionInfo.self, f: { StickerPackCollectionInfo(decoder: $0) }) + declareEncodable(StickerPackItem.self, f: { StickerPackItem(decoder: $0) }) + declareEncodable(LocalFileReferenceMediaResource.self, f: { LocalFileReferenceMediaResource(decoder: $0) }) + declareEncodable(OutgoingMessageInfoAttribute.self, f: { OutgoingMessageInfoAttribute(decoder: $0) }) + declareEncodable(ForwardSourceInfoAttribute.self, f: { ForwardSourceInfoAttribute(decoder: $0) }) + declareEncodable(SourceReferenceMessageAttribute.self, f: { SourceReferenceMessageAttribute(decoder: $0) }) + declareEncodable(EditedMessageAttribute.self, f: { EditedMessageAttribute(decoder: $0) }) + declareEncodable(ReplyMarkupMessageAttribute.self, f: { ReplyMarkupMessageAttribute(decoder: $0) }) + declareEncodable(CachedResolvedByNamePeer.self, f: { CachedResolvedByNamePeer(decoder: $0) }) + declareEncodable(OutgoingChatContextResultMessageAttribute.self, f: { OutgoingChatContextResultMessageAttribute(decoder: $0) }) + declareEncodable(HttpReferenceMediaResource.self, f: { HttpReferenceMediaResource(decoder: $0) }) + declareEncodable(WebFileReferenceMediaResource.self, f: { WebFileReferenceMediaResource(decoder: $0) }) + declareEncodable(EmptyMediaResource.self, f: { EmptyMediaResource(decoder: $0) }) + declareEncodable(TelegramSecretChat.self, f: { TelegramSecretChat(decoder: $0) }) + declareEncodable(SecretChatState.self, f: { SecretChatState(decoder: $0) }) + declareEncodable(SecretChatIncomingEncryptedOperation.self, f: { SecretChatIncomingEncryptedOperation(decoder: $0) }) + declareEncodable(SecretChatIncomingDecryptedOperation.self, f: { SecretChatIncomingDecryptedOperation(decoder: $0) }) + declareEncodable(SecretChatOutgoingOperation.self, f: { SecretChatOutgoingOperation(decoder: $0) }) + declareEncodable(SecretFileMediaResource.self, f: { SecretFileMediaResource(decoder: $0) }) + declareEncodable(CloudChatRemoveMessagesOperation.self, f: { CloudChatRemoveMessagesOperation(decoder: $0) }) + declareEncodable(AutoremoveTimeoutMessageAttribute.self, f: { AutoremoveTimeoutMessageAttribute(decoder: $0) }) + declareEncodable(GlobalNotificationSettings.self, f: { GlobalNotificationSettings(decoder: $0) }) + declareEncodable(CloudChatRemoveChatOperation.self, f: { CloudChatRemoveChatOperation(decoder: $0) }) + declareEncodable(SynchronizePinnedChatsOperation.self, f: { SynchronizePinnedChatsOperation(decoder: $0) }) + declareEncodable(SynchronizeConsumeMessageContentsOperation.self, f: { SynchronizeConsumeMessageContentsOperation(decoder: $0) }) + declareEncodable(RecentMediaItem.self, f: { RecentMediaItem(decoder: $0) }) + declareEncodable(RecentPeerItem.self, f: { RecentPeerItem(decoder: $0) }) + declareEncodable(RecentHashtagItem.self, f: { RecentHashtagItem(decoder: $0) }) + declareEncodable(LoggedOutAccountAttribute.self, f: { LoggedOutAccountAttribute(decoder: $0) }) + declareEncodable(AccountEnvironmentAttribute.self, f: { AccountEnvironmentAttribute(decoder: $0) }) + declareEncodable(AccountSortOrderAttribute.self, f: { AccountSortOrderAttribute(decoder: $0) }) + declareEncodable(CloudChatClearHistoryOperation.self, f: { CloudChatClearHistoryOperation(decoder: $0) }) + declareEncodable(OutgoingContentInfoMessageAttribute.self, f: { OutgoingContentInfoMessageAttribute(decoder: $0) }) + declareEncodable(ConsumableContentMessageAttribute.self, f: { ConsumableContentMessageAttribute(decoder: $0) }) + declareEncodable(TelegramMediaGame.self, f: { TelegramMediaGame(decoder: $0) }) + declareEncodable(TelegramMediaInvoice.self, f: { TelegramMediaInvoice(decoder: $0) }) + declareEncodable(TelegramMediaWebFile.self, f: { TelegramMediaWebFile(decoder: $0) }) + declareEncodable(SynchronizeInstalledStickerPacksOperation.self, f: { SynchronizeInstalledStickerPacksOperation(decoder: $0) }) + declareEncodable(FeaturedStickerPackItem.self, f: { FeaturedStickerPackItem(decoder: $0) }) + declareEncodable(SynchronizeMarkFeaturedStickerPacksAsSeenOperation.self, f: { SynchronizeMarkFeaturedStickerPacksAsSeenOperation(decoder: $0) }) + declareEncodable(ArchivedStickerPacksInfo.self, f: { ArchivedStickerPacksInfo(decoder: $0) }) + declareEncodable(SynchronizeChatInputStateOperation.self, f: { SynchronizeChatInputStateOperation(decoder: $0) }) + declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) }) + declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) + declareEncodable(SynchronizeRecentlyUsedMediaOperation.self, f: { SynchronizeRecentlyUsedMediaOperation(decoder: $0) }) + declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) + declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) + declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) }) + declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) }) + declareEncodable(NetworkSettings.self, f: { NetworkSettings(decoder: $0) }) + declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) }) + declareEncodable(LimitsConfiguration.self, f: { LimitsConfiguration(decoder: $0) }) + declareEncodable(VoipConfiguration.self, f: { VoipConfiguration(decoder: $0) }) + declareEncodable(SuggestedLocalizationEntry.self, f: { SuggestedLocalizationEntry(decoder: $0) }) + declareEncodable(SynchronizeLocalizationUpdatesOperation.self, f: { SynchronizeLocalizationUpdatesOperation(decoder: $0) }) + declareEncodable(ChannelMessageStateVersionAttribute.self, f: { ChannelMessageStateVersionAttribute(decoder: $0) }) + declareEncodable(PeerGroupMessageStateVersionAttribute.self, f: { PeerGroupMessageStateVersionAttribute(decoder: $0) }) + declareEncodable(CachedSecretChatData.self, f: { CachedSecretChatData(decoder: $0) }) + declareEncodable(TemporaryTwoStepPasswordToken.self, f: { TemporaryTwoStepPasswordToken(decoder: $0) }) + declareEncodable(AuthorSignatureMessageAttribute.self, f: { AuthorSignatureMessageAttribute(decoder: $0) }) + declareEncodable(TelegramMediaExpiredContent.self, f: { TelegramMediaExpiredContent(decoder: $0) }) + declareEncodable(SavedStickerItem.self, f: { SavedStickerItem(decoder: $0) }) + declareEncodable(ConsumablePersonalMentionMessageAttribute.self, f: { ConsumablePersonalMentionMessageAttribute(decoder: $0) }) + declareEncodable(ConsumePersonalMessageAction.self, f: { ConsumePersonalMessageAction(decoder: $0) }) + declareEncodable(CachedStickerPack.self, f: { CachedStickerPack(decoder: $0) }) + declareEncodable(LoggingSettings.self, f: { LoggingSettings(decoder: $0) }) + declareEncodable(CachedLocalizationInfos.self, f: { CachedLocalizationInfos(decoder: $0) }) + declareEncodable(CachedSecureIdConfiguration.self, f: { CachedSecureIdConfiguration(decoder: $0) }) + declareEncodable(CachedWallpapersConfiguration.self, f: { CachedWallpapersConfiguration(decoder: $0) }) + declareEncodable(SynchronizeGroupedPeersOperation.self, f: { SynchronizeGroupedPeersOperation(decoder: $0) }) + declareEncodable(ContentPrivacySettings.self, f: { ContentPrivacySettings(decoder: $0) }) + declareEncodable(TelegramDeviceContactImportedData.self, f: { TelegramDeviceContactImportedData(decoder: $0) }) + declareEncodable(SecureFileMediaResource.self, f: { SecureFileMediaResource(decoder: $0) }) + declareEncodable(CachedStickerQueryResult.self, f: { CachedStickerQueryResult(decoder: $0) }) + declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) }) + declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) }) + declareEncodable(SynchronizeAppLogEventsOperation.self, f: { SynchronizeAppLogEventsOperation(decoder: $0) }) + declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) }) + declareEncodable(AppChangelogState.self, f: { AppChangelogState(decoder: $0) }) + declareEncodable(AppConfiguration.self, f: { AppConfiguration(decoder: $0) }) + declareEncodable(JSON.self, f: { JSON(decoder: $0) }) + declareEncodable(SearchBotsConfiguration.self, f: { SearchBotsConfiguration(decoder: $0) }) + declareEncodable(AutodownloadSettings.self, f: { AutodownloadSettings(decoder: $0 )}) + declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) + declareEncodable(TelegramMediaUnsupported.self, f: { TelegramMediaUnsupported(decoder: $0) }) + declareEncodable(ContactsSettings.self, f: { ContactsSettings(decoder: $0) }) + declareEncodable(EmojiKeywordCollectionInfo.self, f: { EmojiKeywordCollectionInfo(decoder: $0) }) + declareEncodable(EmojiKeywordItem.self, f: { EmojiKeywordItem(decoder: $0) }) + declareEncodable(SynchronizeEmojiKeywordsOperation.self, f: { SynchronizeEmojiKeywordsOperation(decoder: $0) }) + + declareEncodable(CloudPhotoSizeMediaResource.self, f: { CloudPhotoSizeMediaResource(decoder: $0) }) + declareEncodable(CloudDocumentSizeMediaResource.self, f: { CloudDocumentSizeMediaResource(decoder: $0) }) + declareEncodable(CloudPeerPhotoSizeMediaResource.self, f: { CloudPeerPhotoSizeMediaResource(decoder: $0) }) + declareEncodable(CloudStickerPackThumbnailMediaResource.self, f: { CloudStickerPackThumbnailMediaResource(decoder: $0) }) + declareEncodable(AccountBackupDataAttribute.self, f: { AccountBackupDataAttribute(decoder: $0) }) + declareEncodable(ContentRequiresValidationMessageAttribute.self, f: { ContentRequiresValidationMessageAttribute(decoder: $0) }) + + return +}() + +public func initializeAccountManagement() { + let _ = declaredEncodables +} + +public func rootPathForBasePath(_ appGroupPath: String) -> String { + return appGroupPath + "/telegram-data" +} + +public func performAppGroupUpgrades(appGroupPath: String, rootPath: String) { + let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: rootPath), withIntermediateDirectories: true, attributes: nil) + + do { + var resourceValues = URLResourceValues() + resourceValues.isExcludedFromBackup = true + var mutableUrl = URL(fileURLWithPath: rootPath) + try mutableUrl.setResourceValues(resourceValues) + } catch let e { + print("\(e)") + } + + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: appGroupPath), includingPropertiesForKeys: [], options: []) { + for url in files { + if url.lastPathComponent == "accounts-metadata" || + url.lastPathComponent.hasSuffix("logs") || + url.lastPathComponent.hasPrefix("account-") { + let _ = try? FileManager.default.moveItem(at: url, to: URL(fileURLWithPath: rootPath + "/" + url.lastPathComponent)) + } + } + } +} + +public final class TemporaryAccount { + public let id: AccountRecordId + public let basePath: String + public let postbox: Postbox + + init(id: AccountRecordId, basePath: String, postbox: Postbox) { + self.id = id + self.basePath = basePath + self.postbox = postbox + } +} + +public func temporaryAccount(manager: AccountManager, rootPath: String, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + return manager.allocatedTemporaryAccountId() + |> mapToSignal { id -> Signal in + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters) + |> mapToSignal { result -> Signal in + switch result { + case .upgrading: + return .complete() + case let .postbox(postbox): + return .single(TemporaryAccount(id: id, basePath: path, postbox: postbox)) + } + } + } +} + +public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkInitializationArguments, supplementary: Bool, manager: AccountManager, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + return manager.currentAccountRecord(allocateIfNotExists: allocateIfNotExists) + |> distinctUntilChanged(isEqual: { lhs, rhs in + return lhs?.0 == rhs?.0 + }) + |> mapToSignal { record -> Signal in + if let record = record { + let reload = ValuePromise(true, ignoreRepeated: false) + return reload.get() + |> mapToSignal { _ -> Signal in + let beginWithTestingEnvironment = record.1.contains(where: { attribute in + if let attribute = attribute as? AccountEnvironmentAttribute, case .test = attribute.environment { + return true + } else { + return false + } + }) + return accountWithId(accountManager: manager, networkArguments: networkArguments, id: record.0, encryptionParameters: encryptionParameters, supplementary: supplementary, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, backupData: nil, auxiliaryMethods: auxiliaryMethods) + |> mapToSignal { accountResult -> Signal in + let postbox: Postbox + let initialKind: AccountKind + switch accountResult { + case .upgrading: + return .complete() + case let .unauthorized(account): + postbox = account.postbox + initialKind = .unauthorized + case let .authorized(account): + postbox = account.postbox + initialKind = .authorized + } + let updatedKind = postbox.stateView() + |> map { view -> Bool in + let kind: AccountKind + if view.state is AuthorizedAccountState { + kind = .authorized + } else { + kind = .unauthorized + } + if kind != initialKind { + return true + } else { + return false + } + } + |> distinctUntilChanged + + return Signal { subscriber in + subscriber.putNext(accountResult) + + return updatedKind.start(next: { value in + if value { + reload.set(true) + } + }) + } + } + } + } else { + return .single(nil) + } + } +} + +public func logoutFromAccount(id: AccountRecordId, accountManager: AccountManager, alreadyLoggedOutRemotely: Bool) -> Signal { + Logger.shared.log("AccountManager", "logoutFromAccount \(id)") + return accountManager.transaction { transaction -> Void in + transaction.updateRecord(id, { current in + if alreadyLoggedOutRemotely { + return nil + } else if let current = current { + var found = false + for attribute in current.attributes { + if attribute is LoggedOutAccountAttribute { + found = true + break + } + } + if found { + return current + } else { + return AccountRecord(id: current.id, attributes: current.attributes + [LoggedOutAccountAttribute()], temporarySessionId: nil) + } + } else { + return nil + } + }) + } +} + +public func managedCleanupAccounts(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { + let currentTemporarySessionId = accountManager.temporarySessionId + return Signal { subscriber in + let loggedOutAccounts = Atomic<[AccountRecordId: MetaDisposable]>(value: [:]) + let _ = (accountManager.transaction { transaction -> Void in + for record in transaction.getRecords() { + if let temporarySessionId = record.temporarySessionId, temporarySessionId != currentTemporarySessionId { + transaction.updateRecord(record.id, { _ in + return nil + }) + } + } + }).start() + let disposable = accountManager.accountRecords().start(next: { view in + var disposeList: [(AccountRecordId, MetaDisposable)] = [] + var beginList: [(AccountRecordId, [AccountRecordAttribute], MetaDisposable)] = [] + let _ = loggedOutAccounts.modify { disposables in + var validIds: [AccountRecordId: [AccountRecordAttribute]] = [:] + outer: for record in view.records { + for attribute in record.attributes { + if attribute is LoggedOutAccountAttribute { + validIds[record.id] = record.attributes + continue outer + } + } + } + + var disposables = disposables + + for id in disposables.keys { + if validIds[id] == nil { + disposeList.append((id, disposables[id]!)) + } + } + + for (id, _) in disposeList { + disposables.removeValue(forKey: id) + } + + for (id, attributes) in validIds { + if disposables[id] == nil { + let disposable = MetaDisposable() + beginList.append((id, attributes, disposable)) + disposables[id] = disposable + } + } + + return disposables + } + for (_, disposable) in disposeList { + disposable.dispose() + } + for (id, attributes, disposable) in beginList { + Logger.shared.log("managedCleanupAccounts", "cleanup \(id), current is \(String(describing: view.currentRecord?.id))") + disposable.set(cleanupAccount(networkArguments: networkArguments, accountManager: accountManager, id: id, encryptionParameters: encryptionParameters, attributes: attributes, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods).start()) + } + + var validPaths = Set() + for record in view.records { + if let temporarySessionId = record.temporarySessionId, temporarySessionId != currentTemporarySessionId { + continue + } + validPaths.insert("\(accountRecordIdPathName(record.id))") + } + if let record = view.currentAuthAccount { + validPaths.insert("\(accountRecordIdPathName(record.id))") + } + + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath), includingPropertiesForKeys: [], options: []) { + for url in files { + if url.lastPathComponent.hasPrefix("account-") { + if !validPaths.contains(url.lastPathComponent) { + try? FileManager.default.removeItem(at: url) + } + } + } + } + }) + + return ActionDisposable { + disposable.dispose() + } + } +} + +private func cleanupAccount(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, attributes: [AccountRecordAttribute], rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { + let beginWithTestingEnvironment = attributes.contains(where: { attribute in + if let attribute = attribute as? AccountEnvironmentAttribute, case .test = attribute.environment { + return true + } else { + return false + } + }) + return accountWithId(accountManager: accountManager, networkArguments: networkArguments, id: id, encryptionParameters: encryptionParameters, supplementary: true, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, backupData: nil, auxiliaryMethods: auxiliaryMethods) + |> mapToSignal { account -> Signal in + switch account { + case .upgrading: + return .complete() + case .unauthorized: + return .complete() + case let .authorized(account): + account.shouldBeServiceTaskMaster.set(.single(.always)) + return account.network.request(Api.functions.auth.logOut()) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + account.shouldBeServiceTaskMaster.set(.single(.never)) + return accountManager.transaction { transaction -> Void in + transaction.updateRecord(id, { _ in + return nil + }) + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountSortOrderAttribute.swift b/submodules/TelegramCore/TelegramCore/AccountSortOrderAttribute.swift new file mode 100644 index 0000000000..371e66dd43 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountSortOrderAttribute.swift @@ -0,0 +1,32 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public final class AccountSortOrderAttribute: AccountRecordAttribute { + public let order: Int32 + + public init(order: Int32) { + self.order = order + } + + public init(decoder: PostboxDecoder) { + self.order = decoder.decodeInt32ForKey("order", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.order, forKey: "order") + } + + public func isEqual(to: AccountRecordAttribute) -> Bool { + guard let to = to as? AccountSortOrderAttribute else { + return false + } + if self.order != to.order { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountState.swift b/submodules/TelegramCore/TelegramCore/AccountState.swift new file mode 100644 index 0000000000..897905941c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountState.swift @@ -0,0 +1,407 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private enum SentAuthorizationCodeTypeValue: Int32 { + case otherSession = 0 + case sms = 1 + case call = 2 + case flashCall = 3 +} + +public enum SentAuthorizationCodeType: PostboxCoding, Equatable { + case otherSession(length: Int32) + case sms(length: Int32) + case call(length: Int32) + case flashCall(pattern: String) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case SentAuthorizationCodeTypeValue.otherSession.rawValue: + self = .otherSession(length: decoder.decodeInt32ForKey("l", orElse: 0)) + case SentAuthorizationCodeTypeValue.sms.rawValue: + self = .sms(length: decoder.decodeInt32ForKey("l", orElse: 0)) + case SentAuthorizationCodeTypeValue.call.rawValue: + self = .call(length: decoder.decodeInt32ForKey("l", orElse: 0)) + case SentAuthorizationCodeTypeValue.flashCall.rawValue: + self = .flashCall(pattern: decoder.decodeStringForKey("p", orElse: "")) + default: + preconditionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .otherSession(length): + encoder.encodeInt32(SentAuthorizationCodeTypeValue.otherSession.rawValue, forKey: "v") + encoder.encodeInt32(length, forKey: "l") + case let .sms(length): + encoder.encodeInt32(SentAuthorizationCodeTypeValue.sms.rawValue, forKey: "v") + encoder.encodeInt32(length, forKey: "l") + case let .call(length): + encoder.encodeInt32(SentAuthorizationCodeTypeValue.call.rawValue, forKey: "v") + encoder.encodeInt32(length, forKey: "l") + case let .flashCall(pattern): + encoder.encodeInt32(SentAuthorizationCodeTypeValue.flashCall.rawValue, forKey: "v") + encoder.encodeString(pattern, forKey: "p") + } + } + + public static func ==(lhs: SentAuthorizationCodeType, rhs: SentAuthorizationCodeType) -> Bool { + switch lhs { + case let .otherSession(length): + if case .otherSession(length) = rhs { + return true + } else { + return false + } + case let .sms(length): + if case .sms(length) = rhs { + return true + } else { + return false + } + case let .call(length): + if case .call(length) = rhs { + return true + } else { + return false + } + case let .flashCall(pattern): + if case .flashCall(pattern) = rhs { + return true + } else { + return false + } + } + } +} + +public enum AuthorizationCodeNextType: Int32 { + case sms = 0 + case call = 1 + case flashCall = 2 +} + +private enum UnauthorizedAccountStateContentsValue: Int32 { + case empty = 0 + case phoneEntry = 1 + case confirmationCodeEntry = 2 + case passwordEntry = 3 + case signUp = 5 + case passwordRecovery = 6 + case awaitingAccountReset = 7 +} + +public struct UnauthorizedAccountTermsOfService: PostboxCoding, Equatable { + public let id: String + public let text: String + public let entities: [MessageTextEntity] + public let ageConfirmation: Int32? + + init(id: String, text: String, entities: [MessageTextEntity], ageConfirmation: Int32?) { + self.id = id + self.text = text + self.entities = entities + self.ageConfirmation = ageConfirmation + } + + public init(decoder: PostboxDecoder) { + self.id = decoder.decodeStringForKey("id", orElse: "") + self.text = decoder.decodeStringForKey("text", orElse: "") + self.entities = (try? decoder.decodeObjectArrayWithCustomDecoderForKey("entities", decoder: { MessageTextEntity(decoder: $0) })) ?? [] + self.ageConfirmation = decoder.decodeOptionalInt32ForKey("ageConfirmation") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.id, forKey: "id") + encoder.encodeString(self.text, forKey: "text") + encoder.encodeObjectArray(self.entities, forKey: "entities") + if let ageConfirmation = self.ageConfirmation { + encoder.encodeInt32(ageConfirmation, forKey: "ageConfirmation") + } else { + encoder.encodeNil(forKey: "ageConfirmation") + } + } +} + +extension UnauthorizedAccountTermsOfService { + init?(apiTermsOfService: Api.help.TermsOfService) { + switch apiTermsOfService { + case let .termsOfService(_, id, text, entities, minAgeConfirm): + let idData: String + switch id { + case let .dataJSON(data): + idData = data + } + self.init(id: idData, text: text, entities: messageTextEntitiesFromApiEntities(entities), ageConfirmation: minAgeConfirm) + } + } +} + +public enum UnauthorizedAccountStateContents: PostboxCoding, Equatable { + case empty + case phoneEntry(countryCode: Int32, number: String) + case confirmationCodeEntry(number: String, type: SentAuthorizationCodeType, hash: String, timeout: Int32?, nextType: AuthorizationCodeNextType?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?, syncContacts: Bool) + case passwordEntry(hint: String, number: String?, code: String?, suggestReset: Bool, syncContacts: Bool) + case passwordRecovery(hint: String, number: String?, code: String?, emailPattern: String, syncContacts: Bool) + case awaitingAccountReset(protectedUntil: Int32, number: String?, syncContacts: Bool) + case signUp(number: String, codeHash: String, code: String, firstName: String, lastName: String, termsOfService: UnauthorizedAccountTermsOfService?, syncContacts: Bool) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case UnauthorizedAccountStateContentsValue.empty.rawValue: + self = .empty + case UnauthorizedAccountStateContentsValue.phoneEntry.rawValue: + self = .phoneEntry(countryCode: decoder.decodeInt32ForKey("cc", orElse: 1), number: decoder.decodeStringForKey("n", orElse: "")) + case UnauthorizedAccountStateContentsValue.confirmationCodeEntry.rawValue: + var nextType: AuthorizationCodeNextType? + if let value = decoder.decodeOptionalInt32ForKey("nt") { + nextType = AuthorizationCodeNextType(rawValue: value) + } + var termsOfService: (UnauthorizedAccountTermsOfService, Bool)? + if let termsValue = decoder.decodeObjectForKey("tos", decoder: { UnauthorizedAccountTermsOfService(decoder: $0) }) as? UnauthorizedAccountTermsOfService { + termsOfService = (termsValue, decoder.decodeInt32ForKey("tose", orElse: 0) != 0) + } + self = .confirmationCodeEntry(number: decoder.decodeStringForKey("num", orElse: ""), type: decoder.decodeObjectForKey("t", decoder: { SentAuthorizationCodeType(decoder: $0) }) as! SentAuthorizationCodeType, hash: decoder.decodeStringForKey("h", orElse: ""), timeout: decoder.decodeOptionalInt32ForKey("tm"), nextType: nextType, termsOfService: termsOfService, syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + case UnauthorizedAccountStateContentsValue.passwordEntry.rawValue: + self = .passwordEntry(hint: decoder.decodeStringForKey("h", orElse: ""), number: decoder.decodeOptionalStringForKey("n"), code: decoder.decodeOptionalStringForKey("c"), suggestReset: decoder.decodeInt32ForKey("suggestReset", orElse: 0) != 0, syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + case UnauthorizedAccountStateContentsValue.passwordRecovery.rawValue: + self = .passwordRecovery(hint: decoder.decodeStringForKey("hint", orElse: ""), number: decoder.decodeOptionalStringForKey("number"), code: decoder.decodeOptionalStringForKey("code"), emailPattern: decoder.decodeStringForKey("emailPattern", orElse: ""), syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + case UnauthorizedAccountStateContentsValue.awaitingAccountReset.rawValue: + self = .awaitingAccountReset(protectedUntil: decoder.decodeInt32ForKey("protectedUntil", orElse: 0), number: decoder.decodeOptionalStringForKey("number"), syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + case UnauthorizedAccountStateContentsValue.signUp.rawValue: + self = .signUp(number: decoder.decodeStringForKey("n", orElse: ""), codeHash: decoder.decodeStringForKey("h", orElse: ""), code: decoder.decodeStringForKey("c", orElse: ""), firstName: decoder.decodeStringForKey("f", orElse: ""), lastName: decoder.decodeStringForKey("l", orElse: ""), termsOfService: decoder.decodeObjectForKey("tos", decoder: { UnauthorizedAccountTermsOfService(decoder: $0) }) as? UnauthorizedAccountTermsOfService, syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + default: + assertionFailure() + self = .empty + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .empty: + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.empty.rawValue, forKey: "v") + case let .phoneEntry(countryCode, number): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.phoneEntry.rawValue, forKey: "v") + encoder.encodeInt32(countryCode, forKey: "cc") + encoder.encodeString(number, forKey: "n") + case let .confirmationCodeEntry(number, type, hash, timeout, nextType, termsOfService, syncContacts): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.confirmationCodeEntry.rawValue, forKey: "v") + encoder.encodeString(number, forKey: "num") + encoder.encodeObject(type, forKey: "t") + encoder.encodeString(hash, forKey: "h") + if let timeout = timeout { + encoder.encodeInt32(timeout, forKey: "tm") + } else { + encoder.encodeNil(forKey: "tm") + } + if let nextType = nextType { + encoder.encodeInt32(nextType.rawValue, forKey: "nt") + } else { + encoder.encodeNil(forKey: "nt") + } + if let (termsOfService, exclusive) = termsOfService { + encoder.encodeObject(termsOfService, forKey: "tos") + encoder.encodeInt32(exclusive ? 1 : 0, forKey: "tose") + } else { + encoder.encodeNil(forKey: "tos") + } + encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") + case let .passwordEntry(hint, number, code, suggestReset, syncContacts): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.passwordEntry.rawValue, forKey: "v") + encoder.encodeString(hint, forKey: "h") + if let number = number { + encoder.encodeString(number, forKey: "n") + } else { + encoder.encodeNil(forKey: "n") + } + if let code = code { + encoder.encodeString(code, forKey: "c") + } else { + encoder.encodeNil(forKey: "c") + } + encoder.encodeInt32(suggestReset ? 1 : 0, forKey: "suggestReset") + encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") + case let .passwordRecovery(hint, number, code, emailPattern, syncContacts): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.passwordRecovery.rawValue, forKey: "v") + encoder.encodeString(hint, forKey: "hint") + if let number = number { + encoder.encodeString(number, forKey: "number") + } else { + encoder.encodeNil(forKey: "number") + } + if let code = code { + encoder.encodeString(code, forKey: "code") + } else { + encoder.encodeNil(forKey: "code") + } + encoder.encodeString(emailPattern, forKey: "emailPattern") + encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") + case let .awaitingAccountReset(protectedUntil, number, syncContacts): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.awaitingAccountReset.rawValue, forKey: "v") + encoder.encodeInt32(protectedUntil, forKey: "protectedUntil") + if let number = number { + encoder.encodeString(number, forKey: "number") + } else { + encoder.encodeNil(forKey: "number") + } + encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") + case let .signUp(number, codeHash, code, firstName, lastName, termsOfService, syncContacts): + encoder.encodeInt32(UnauthorizedAccountStateContentsValue.signUp.rawValue, forKey: "v") + encoder.encodeString(number, forKey: "n") + encoder.encodeString(codeHash, forKey: "h") + encoder.encodeString(code, forKey: "c") + encoder.encodeString(firstName, forKey: "f") + encoder.encodeString(lastName, forKey: "l") + if let termsOfService = termsOfService { + encoder.encodeObject(termsOfService, forKey: "tos") + } else { + encoder.encodeNil(forKey: "tos") + } + encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") + } + } + + public static func ==(lhs: UnauthorizedAccountStateContents, rhs: UnauthorizedAccountStateContents) -> Bool { + switch lhs { + case .empty: + if case .empty = rhs { + return true + } else { + return false + } + case let .phoneEntry(countryCode, number): + if case .phoneEntry(countryCode, number) = rhs { + return true + } else { + return false + } + case let .confirmationCodeEntry(lhsNumber, lhsType, lhsHash, lhsTimeout, lhsNextType, lhsTermsOfService, lhsSyncContacts): + if case let .confirmationCodeEntry(rhsNumber, rhsType, rhsHash, rhsTimeout, rhsNextType, rhsTermsOfService, rhsSyncContacts) = rhs { + if lhsNumber != rhsNumber { + return false + } + if lhsType != rhsType { + return false + } + if lhsHash != rhsHash { + return false + } + if lhsTimeout != rhsTimeout { + return false + } + if lhsNextType != rhsNextType { + return false + } + if lhsTermsOfService?.0 != rhsTermsOfService?.0 { + return false + } + if lhsTermsOfService?.1 != rhsTermsOfService?.1 { + return false + } + if lhsSyncContacts != rhsSyncContacts { + return false + } + return true + } else { + return false + } + case let .passwordEntry(lhsHint, lhsNumber, lhsCode, lhsSuggestReset, lhsSyncContacts): + if case let .passwordEntry(rhsHint, rhsNumber, rhsCode, rhsSuggestReset, rhsSyncContacts) = rhs { + return lhsHint == rhsHint && lhsNumber == rhsNumber && lhsCode == rhsCode && lhsSuggestReset == rhsSuggestReset && lhsSyncContacts == rhsSyncContacts + } else { + return false + } + case let .passwordRecovery(lhsHint, lhsNumber, lhsCode, lhsEmailPattern, lhsSyncContacts): + if case let .passwordRecovery(rhsHint, rhsNumber, rhsCode, rhsEmailPattern, rhsSyncContacts) = rhs { + return lhsHint == rhsHint && lhsNumber == rhsNumber && lhsCode == rhsCode && lhsEmailPattern == rhsEmailPattern && lhsSyncContacts == rhsSyncContacts + } else { + return false + } + case let .awaitingAccountReset(lhsProtectedUntil, lhsNumber, lhsSyncContacts): + if case let .awaitingAccountReset(rhsProtectedUntil, rhsNumber, rhsSyncContacts) = rhs { + return lhsProtectedUntil == rhsProtectedUntil && lhsNumber == rhsNumber && lhsSyncContacts == rhsSyncContacts + } else { + return false + } + case let .signUp(number, codeHash, code, firstName, lastName, termsOfService, syncContacts): + if case .signUp(number, codeHash, code, firstName, lastName, termsOfService, syncContacts) = rhs { + return true + } else { + return false + } + } + } +} + +public final class UnauthorizedAccountState: AccountState { + public let isTestingEnvironment: Bool + public let masterDatacenterId: Int32 + public let contents: UnauthorizedAccountStateContents + + public init(isTestingEnvironment: Bool, masterDatacenterId: Int32, contents: UnauthorizedAccountStateContents) { + self.isTestingEnvironment = isTestingEnvironment + self.masterDatacenterId = masterDatacenterId + self.contents = contents + } + + public init(decoder: PostboxDecoder) { + self.isTestingEnvironment = decoder.decodeInt32ForKey("isTestingEnvironment", orElse: 0) != 0 + self.masterDatacenterId = decoder.decodeInt32ForKey("dc", orElse: 0) + self.contents = decoder.decodeObjectForKey("c", decoder: { UnauthorizedAccountStateContents(decoder: $0) }) as! UnauthorizedAccountStateContents + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.isTestingEnvironment ? 1 : 0, forKey: "isTestingEnvironment") + encoder.encodeInt32(self.masterDatacenterId, forKey: "dc") + encoder.encodeObject(self.contents, forKey: "c") + } + + public func equalsTo(_ other: AccountState) -> Bool { + guard let other = other as? UnauthorizedAccountState else { + return false + } + if self.isTestingEnvironment != other.isTestingEnvironment { + return false + } + if self.masterDatacenterId != other.masterDatacenterId { + return false + } + if self.contents != other.contents { + return false + } + return true + } +} + +extension SentAuthorizationCodeType { + init(apiType: Api.auth.SentCodeType) { + switch apiType { + case let .sentCodeTypeApp(length): + self = .otherSession(length: length) + case let .sentCodeTypeSms(length): + self = .sms(length: length) + case let .sentCodeTypeCall(length): + self = .call(length: length) + case let .sentCodeTypeFlashCall(pattern): + self = .flashCall(pattern: pattern) + } + } +} + +extension AuthorizationCodeNextType { + init(apiType: Api.auth.CodeType) { + switch apiType { + case .codeTypeSms: + self = .sms + case .codeTypeCall: + self = .call + case .codeTypeFlashCall: + self = .flashCall + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift b/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift new file mode 100644 index 0000000000..d6e9890cf8 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift @@ -0,0 +1,2821 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private func peerIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set { + var peerIds = Set() + + for group in groups { + for update in group.updates { + for peerId in update.peerIds { + peerIds.insert(peerId) + } + } + for user in group.users { + peerIds.insert(user.peerId) + } + for chat in group.chats { + peerIds.insert(chat.peerId) + } + switch group { + case let .updateChannelPts(channelId, _, _): + peerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)) + default: + break + } + } + + return peerIds +} + +private func activeChannelsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set { + var peerIds = Set() + + for group in groups { + for chat in group.chats { + switch chat { + case .channel: + if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel { + if channel.participationStatus == .member { + peerIds.insert(channel.id) + } + } + default: + break + } + } + } + + return peerIds +} + +private func associatedMessageIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set { + var messageIds = Set() + + for group in groups { + for update in group.updates { + if let associatedMessageIds = update.associatedMessageIds { + for messageId in associatedMessageIds { + messageIds.insert(messageId) + } + } + } + } + + return messageIds +} + +private func peerIdsRequiringLocalChatStateFromUpdates(_ updates: [Api.Update]) -> Set { + var peerIds = Set() + for update in updates { + if let messageId = update.messageId { + peerIds.insert(messageId.peerId) + } + switch update { + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + peerIds.insert(peerId) + case let .updateFolderPeers(folderPeers, _, _): + for peer in folderPeers { + switch peer { + case let .folderPeer(peer, _): + peerIds.insert(peer.peerId) + } + } + case let .updateReadChannelInbox(_, _, channelId, _, _, _): + peerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)) + case let .updateReadHistoryInbox(_, _, peer, _, _, _, _): + peerIds.insert(peer.peerId) + case let .updateDraftMessage(peer, draft): + switch draft { + case .draftMessage: + peerIds.insert(peer.peerId) + case .draftMessageEmpty: + break + } + default: + break + } + } + return peerIds +} + +private func peerIdsRequiringLocalChatStateFromUpdateGroups(_ groups: [UpdateGroup]) -> Set { + var peerIds = Set() + + for group in groups { + peerIds.formUnion(peerIdsRequiringLocalChatStateFromUpdates(group.updates)) + } + + return peerIds +} + +private func locallyGeneratedMessageTimestampsFromUpdateGroups(_ groups: [UpdateGroup]) -> [PeerId: [(MessageId.Namespace, Int32)]] { + var messageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]] = [:] + for group in groups { + for update in group.updates { + switch update { + case let .updateServiceNotification(_, date, _, _, _, _): + if let date = date { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 777000) + if messageTimestamps[peerId] == nil { + messageTimestamps[peerId] = [(Namespaces.Message.Local, date)] + } else { + messageTimestamps[peerId]!.append((Namespaces.Message.Local, date)) + } + } + default: + break + } + } + } + + return messageTimestamps +} + +private func peerIdsFromDifference(_ difference: Api.updates.Difference) -> Set { + var peerIds = Set() + + switch difference { + case let .difference(newMessages, _, otherUpdates, chats, users, _): + for message in newMessages { + for peerId in apiMessagePeerIds(message) { + peerIds.insert(peerId) + } + } + for user in users { + peerIds.insert(user.peerId) + } + for chat in chats { + peerIds.insert(chat.peerId) + } + for update in otherUpdates { + for peerId in update.peerIds { + peerIds.insert(peerId) + } + } + case .differenceEmpty: + break + case let .differenceSlice(newMessages, _, otherUpdates, chats, users, _): + for message in newMessages { + for peerId in apiMessagePeerIds(message) { + peerIds.insert(peerId) + } + } + for user in users { + peerIds.insert(user.peerId) + } + for chat in chats { + peerIds.insert(chat.peerId) + } + for update in otherUpdates { + for peerId in update.peerIds { + peerIds.insert(peerId) + } + } + case .differenceTooLong: + assertionFailure() + break + } + + return peerIds +} + +private func activeChannelsFromDifference(_ difference: Api.updates.Difference) -> Set { + var peerIds = Set() + + var chats: [Api.Chat] = [] + switch difference { + case let .difference(difference): + chats = difference.chats + case .differenceEmpty: + break + case let .differenceSlice(differenceSlice): + chats = differenceSlice.chats + case .differenceTooLong: + break + } + + for chat in chats { + switch chat { + case .channel: + if let channel = parseTelegramGroupOrChannel(chat: chat) as? TelegramChannel { + if channel.participationStatus == .member { + peerIds.insert(channel.id) + } + } + default: + break + } + } + + return peerIds +} + +private func associatedMessageIdsFromDifference(_ difference: Api.updates.Difference) -> Set { + var messageIds = Set() + + switch difference { + case let .difference(newMessages, _, otherUpdates, _, _, _): + for message in newMessages { + if let associatedMessageIds = apiMessageAssociatedMessageIds(message) { + for messageId in associatedMessageIds { + messageIds.insert(messageId) + } + } + } + for update in otherUpdates { + if let associatedMessageIds = update.associatedMessageIds { + for messageId in associatedMessageIds { + messageIds.insert(messageId) + } + } + } + case .differenceEmpty: + break + case let .differenceSlice(newMessages, _, otherUpdates, _, _, _): + for message in newMessages { + if let associatedMessageIds = apiMessageAssociatedMessageIds(message) { + for messageId in associatedMessageIds { + messageIds.insert(messageId) + } + } + } + + for update in otherUpdates { + if let associatedMessageIds = update.associatedMessageIds { + for messageId in associatedMessageIds { + messageIds.insert(messageId) + } + } + } + case .differenceTooLong: + break + } + + return messageIds +} + +private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.updates.Difference) -> Set { + var peerIds = Set() + + switch difference { + case let .difference(newMessages, _, otherUpdates, _, _, _): + for message in newMessages { + if let messageId = message.id { + peerIds.insert(messageId.peerId) + } + } + peerIds.formUnion(peerIdsRequiringLocalChatStateFromUpdates(otherUpdates)) + for update in otherUpdates { + if let messageId = update.messageId { + peerIds.insert(messageId.peerId) + } + switch update { + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + peerIds.insert(peerId) + default: + break + } + } + case .differenceEmpty: + break + case let .differenceSlice(newMessages, _, otherUpdates, _, _, _): + for message in newMessages { + if let messageId = message.id { + peerIds.insert(messageId.peerId) + } + } + + peerIds.formUnion(peerIdsRequiringLocalChatStateFromUpdates(otherUpdates)) + for update in otherUpdates { + if let messageId = update.messageId { + peerIds.insert(messageId.peerId) + } + switch update { + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + peerIds.insert(peerId) + default: + break + } + } + case .differenceTooLong: + break + } + + return peerIds +} + +private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.updates.Difference) -> [PeerId: [(MessageId.Namespace, Int32)]] { + var messageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]] = [:] + + var otherUpdates: [Api.Update]? + switch difference { + case let .difference(_, _, apiOtherUpdates, _, _, _): + otherUpdates = apiOtherUpdates + case .differenceEmpty: + break + case let .differenceSlice(_, _, apiOtherUpdates, _, _, _): + otherUpdates = apiOtherUpdates + case .differenceTooLong: + break + } + + if let otherUpdates = otherUpdates { + for update in otherUpdates { + switch update { + case let .updateServiceNotification(_, date, _, _, _, _): + if let date = date { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 777000) + if messageTimestamps[peerId] == nil { + messageTimestamps[peerId] = [(Namespaces.Message.Local, date)] + } else { + messageTimestamps[peerId]!.append((Namespaces.Message.Local, date)) + } + } + default: + break + } + } + } + + return messageTimestamps +} + +private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set, activeChannelIds: Set, associatedMessageIds: Set, peerIdsRequiringLocalChatState: Set, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState { + var peers: [PeerId: Peer] = [:] + var chatStates: [PeerId: PeerChatState] = [:] + + var channelsToPollExplicitely = Set() + + for peerId in peerIds { + if let peer = transaction.getPeer(peerId) { + peers[peerId] = peer + } + + if peerId.namespace == Namespaces.Peer.CloudChannel { + if let channelState = transaction.getPeerChatState(peerId) as? ChannelState { + chatStates[peerId] = channelState + } + } else if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + if let chatState = transaction.getPeerChatState(peerId) as? RegularChatState { + chatStates[peerId] = chatState + } + } + } + + for peerId in activeChannelIds { + if transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) == nil { + channelsToPollExplicitely.insert(peerId) + } else if let channel = transaction.getPeer(peerId) as? TelegramChannel, channel.participationStatus != .member { + channelsToPollExplicitely.insert(peerId) + } + } + + let storedMessages = transaction.filterStoredMessageIds(associatedMessageIds) + var storedMessagesByPeerIdAndTimestamp: [PeerId: Set] = [:] + if !locallyGeneratedMessageTimestamps.isEmpty { + for (peerId, namespacesAndTimestamps) in locallyGeneratedMessageTimestamps { + for (namespace, timestamp) in namespacesAndTimestamps { + if let messageId = transaction.storedMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp) { + if storedMessagesByPeerIdAndTimestamp[peerId] == nil { + storedMessagesByPeerIdAndTimestamp[peerId] = Set([MessageIndex(id: messageId, timestamp: timestamp)]) + } else { + storedMessagesByPeerIdAndTimestamp[peerId]!.insert(MessageIndex(id: messageId, timestamp: timestamp)) + } + } + } + } + } + + var peerChatInfos: [PeerId: PeerChatInfo] = [:] + var readInboxMaxIds: [PeerId: MessageId] = [:] + var cloudReadStates: [PeerId: PeerReadState] = [:] + + for peerId in peerIdsRequiringLocalChatState { + let inclusion = transaction.getPeerChatListInclusion(peerId) + var hasValidInclusion = false + switch inclusion { + case .ifHasMessagesOrOneOf: + hasValidInclusion = true + case .notIncluded: + hasValidInclusion = false + } + if hasValidInclusion { + if let notificationSettings = transaction.getPeerNotificationSettings(peerId) { + peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) + } + } + if let readStates = transaction.getPeerReadStates(peerId) { + for (namespace, state) in readStates { + if namespace == Namespaces.Message.Cloud { + cloudReadStates[peerId] = state + switch state { + case let .idBased(maxIncomingReadId, _, _, _, _): + readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: maxIncomingReadId) + case .indexBased: + break + } + break + } + } + } + } + + return AccountMutableState(initialState: AccountInitialState(state: (transaction.getState() as? AuthorizedAccountState)!.state!, peerIds: peerIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, chatStates: chatStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestamps, cloudReadStates: cloudReadStates, channelsToPollExplicitely: channelsToPollExplicitely), initialPeers: peers, initialReferencedMessageIds: associatedMessageIds, initialStoredMessages: storedMessages, initialReadInboxMaxIds: readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: storedMessagesByPeerIdAndTimestamp) +} + +func initialStateWithUpdateGroups(postbox: Postbox, groups: [UpdateGroup]) -> Signal { + return postbox.transaction { transaction -> AccountMutableState in + let peerIds = peerIdsFromUpdateGroups(groups) + let activeChannelIds = activeChannelsFromUpdateGroups(groups) + let associatedMessageIds = associatedMessageIdsFromUpdateGroups(groups) + let peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatStateFromUpdateGroups(groups) + + return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, associatedMessageIds: associatedMessageIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromUpdateGroups(groups)) + } +} + +func initialStateWithDifference(postbox: Postbox, difference: Api.updates.Difference) -> Signal { + return postbox.transaction { transaction -> AccountMutableState in + let peerIds = peerIdsFromDifference(difference) + let activeChannelIds = activeChannelsFromDifference(difference) + let associatedMessageIds = associatedMessageIdsFromDifference(difference) + let peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatStateFromDifference(difference) + return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, associatedMessageIds: associatedMessageIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromDifference(difference)) + } +} + +func finalStateWithUpdateGroups(postbox: Postbox, network: Network, state: AccountMutableState, groups: [UpdateGroup]) -> Signal { + var updatedState = state + + var hadReset = false + var ptsUpdatesAfterHole: [PtsUpdate] = [] + var qtsUpdatesAfterHole: [QtsUpdate] = [] + var seqGroupsAfterHole: [SeqUpdates] = [] + + for case .reset in groups { + hadReset = true + break + } + + var currentPtsUpdates = ptsUpdates(groups) + currentPtsUpdates.sort(by: { $0.ptsRange.0 < $1.ptsRange.0 }) + + var currentQtsUpdates = qtsUpdates(groups) + currentQtsUpdates.sort(by: { $0.qtsRange.0 < $1.qtsRange.0 }) + + var currentSeqGroups = seqGroups(groups) + currentSeqGroups.sort(by: { $0.seqRange.0 < $1.seqRange.0 }) + + var collectedUpdates: [Api.Update] = [] + + for update in currentPtsUpdates { + if updatedState.state.pts >= update.ptsRange.0 { + if let update = update.update, case .updateWebPage = update { + collectedUpdates.append(update) + } + //skip old update + } + else if ptsUpdatesAfterHole.count == 0 && updatedState.state.pts == update.ptsRange.0 - update.ptsRange.1 { + //TODO: apply pts update + + updatedState.mergeChats(update.chats) + updatedState.mergeUsers(update.users) + + if let ptsUpdate = update.update { + collectedUpdates.append(ptsUpdate) + } + + updatedState.updateState(AuthorizedAccountState.State(pts: update.ptsRange.0, qts: updatedState.state.qts, date: updatedState.state.date, seq: updatedState.state.seq)) + } else { + if ptsUpdatesAfterHole.count == 0 { + Logger.shared.log("State", "update pts hole: \(update.ptsRange.0) != \(updatedState.state.pts) + \(update.ptsRange.1)") + } + ptsUpdatesAfterHole.append(update) + } + } + + for update in currentQtsUpdates { + if updatedState.state.qts >= update.qtsRange.0 + update.qtsRange.1 { + //skip old update + } else if qtsUpdatesAfterHole.count == 0 && updatedState.state.qts == update.qtsRange.0 - update.qtsRange.1 { + //TODO apply qts update + + updatedState.mergeChats(update.chats) + updatedState.mergeUsers(update.users) + + collectedUpdates.append(update.update) + + updatedState.updateState(AuthorizedAccountState.State(pts: updatedState.state.pts, qts: update.qtsRange.0, date: updatedState.state.date, seq: updatedState.state.seq)) + } else { + if qtsUpdatesAfterHole.count == 0 { + Logger.shared.log("State", "update qts hole: \(update.qtsRange.0) != \(updatedState.state.qts) + \(update.qtsRange.1)") + } + qtsUpdatesAfterHole.append(update) + } + } + + for group in currentSeqGroups { + if updatedState.state.seq >= group.seqRange.0 + group.seqRange.1 { + //skip old update + } else if seqGroupsAfterHole.count == 0 && updatedState.state.seq == group.seqRange.0 - group.seqRange.1 { + collectedUpdates.append(contentsOf: group.updates) + + updatedState.mergeChats(group.chats) + updatedState.mergeUsers(group.users) + + updatedState.updateState(AuthorizedAccountState.State(pts: updatedState.state.pts, qts: updatedState.state.qts, date: group.date, seq: group.seqRange.0)) + } else { + if seqGroupsAfterHole.count == 0 { + Logger.shared.log("State", "update seq hole: \(group.seqRange.0) != \(updatedState.state.seq) + \(group.seqRange.1)") + } + seqGroupsAfterHole.append(group) + } + } + + var currentDateGroups = dateGroups(groups) + currentDateGroups.sort(by: { group1, group2 -> Bool in + switch group1 { + case let .withDate(_, date1, _, _): + switch group2 { + case let .withDate(_, date2, _, _): + return date1 < date2 + default: + return false + } + default: + return false + } + }) + + var updatesDate: Int32? + + for group in currentDateGroups { + switch group { + case let .withDate(updates, date, users, chats): + collectedUpdates.append(contentsOf: updates) + + updatedState.mergeChats(chats) + updatedState.mergeUsers(users) + if updatesDate == nil { + updatesDate = date + } + default: + break + } + } + + for case let .updateChannelPts(channelId, pts, ptsCount) in groups { + collectedUpdates.append(Api.Update.updateDeleteChannelMessages(channelId: channelId, messages: [], pts: pts, ptsCount: ptsCount)) + } + + return finalStateWithUpdates(postbox: postbox, network: network, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty, shouldResetChannels: true, updatesDate: updatesDate) +} + +func finalStateWithDifference(postbox: Postbox, network: Network, state: AccountMutableState, difference: Api.updates.Difference) -> Signal { + var updatedState = state + + var messages: [Api.Message] = [] + var encryptedMessages: [Api.EncryptedMessage] = [] + var updates: [Api.Update] = [] + var chats: [Api.Chat] = [] + var users: [Api.User] = [] + + switch difference { + case let .difference(newMessages, newEncryptedMessages, otherUpdates, apiChats, apiUsers, apiState): + messages = newMessages + encryptedMessages = newEncryptedMessages + updates = otherUpdates + chats = apiChats + users = apiUsers + switch apiState { + case let .state(pts, qts, date, seq, _): + updatedState.updateState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq)) + } + case let .differenceEmpty(date, seq): + updatedState.updateState(AuthorizedAccountState.State(pts: updatedState.state.pts, qts: updatedState.state.qts, date: date, seq: seq)) + case let .differenceSlice(newMessages, newEncryptedMessages, otherUpdates, apiChats, apiUsers, apiState): + messages = newMessages + encryptedMessages = newEncryptedMessages + updates = otherUpdates + chats = apiChats + users = apiUsers + switch apiState { + case let .state(pts, qts, date, seq, _): + updatedState.updateState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq)) + } + case .differenceTooLong: + assertionFailure() + break + } + + updatedState.mergeChats(chats) + updatedState.mergeUsers(users) + + for message in messages { + if let preCachedResources = message.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + if let message = StoreMessage(apiMessage: message) { + updatedState.addMessages([message], location: .UpperHistoryBlock) + } + } + + if !encryptedMessages.isEmpty { + updatedState.addSecretMessages(encryptedMessages) + } + + return finalStateWithUpdates(postbox: postbox, network: network, state: updatedState, updates: updates, shouldPoll: false, missingUpdates: false, shouldResetChannels: true, updatesDate: nil) +} + +private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] { + var result: [Api.Update] = [] + + var updatesByChannel: [PeerId: [Api.Update]] = [:] + + for update in updates { + switch update { + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + case let .updateDeleteChannelMessages(channelId, _, _, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + case let .updateNewChannelMessage(message, _, _): + if let peerId = apiMessagePeerId(message) { + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + } else { + result.append(update) + } + case let .updateEditChannelMessage(message, _, _): + if let peerId = apiMessagePeerId(message) { + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + } else { + result.append(update) + } + case let .updateChannelWebPage(channelId, _, _, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + case let .updateChannelAvailableMessages(channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + default: + result.append(update) + } + } + + for (_, updates) in updatesByChannel { + let sortedUpdates = updates.sorted(by: { lhs, rhs in + var lhsPts: Int32? + var rhsPts: Int32? + + switch lhs { + case let .updateDeleteChannelMessages(_, _, pts, _): + lhsPts = pts + case let .updateNewChannelMessage(_, pts, _): + lhsPts = pts + case let .updateChannelWebPage(_, _, pts, _): + lhsPts = pts + case let .updateEditChannelMessage(_, pts, _): + lhsPts = pts + default: + break + } + + switch rhs { + case let .updateDeleteChannelMessages(_, _, pts, _): + rhsPts = pts + case let .updateNewChannelMessage(_, pts, _): + rhsPts = pts + case let .updateChannelWebPage(_, _, pts, _): + rhsPts = pts + case let .updateEditChannelMessage(_, pts, _): + rhsPts = pts + default: + break + } + + if let lhsPts = lhsPts, let rhsPts = rhsPts { + return lhsPts < rhsPts + } else if let _ = lhsPts { + return true + } else { + return false + } + }) + result.append(contentsOf: sortedUpdates) + } + + return result +} + +private func finalStateWithUpdates(postbox: Postbox, network: Network, state: AccountMutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool, shouldResetChannels: Bool, updatesDate: Int32?) -> Signal { + return network.currentGlobalTime + |> take(1) + |> mapToSignal { serverTime -> Signal in + return finalStateWithUpdatesAndServerTime(postbox: postbox, network: network, state: state, updates: updates, shouldPoll: shouldPoll, missingUpdates: missingUpdates, shouldResetChannels: shouldResetChannels, updatesDate: updatesDate, serverTime: Int32(serverTime)) + } +} + +private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Network, state: AccountMutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool, shouldResetChannels: Bool, updatesDate: Int32?, serverTime: Int32) -> Signal { + var updatedState = state + + var channelsToPoll = Set() + + if !updatedState.initialState.channelsToPollExplicitely.isEmpty { + channelsToPoll.formUnion(updatedState.initialState.channelsToPollExplicitely) + } + + for update in sortedUpdates(updates) { + switch update { + case let .updateChannelTooLong(_, channelId, channelPts): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if !channelsToPoll.contains(peerId) { + if let channelPts = channelPts, let channelState = state.chatStates[peerId] as? ChannelState, channelState.pts >= channelPts { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip updateChannelTooLong by pts") + } else { + channelsToPoll.insert(peerId) + } + } + case let .updateDeleteChannelMessages(channelId, messages, pts: pts, ptsCount): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if let previousState = updatedState.chatStates[peerId] as? ChannelState { + if previousState.pts >= pts { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old delete update") + } else if previousState.pts + ptsCount == pts { + updatedState.deleteMessages(messages.map({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })) + updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) + } else { + if !channelsToPoll.contains(peerId) { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) delete pts hole") + channelsToPoll.insert(peerId) + //updatedMissingUpdates = true + } + } + } else { + if !channelsToPoll.contains(peerId) { + //Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) state unknown") + channelsToPoll.insert(peerId) + } + } + case let .updateEditChannelMessage(apiMessage, pts, ptsCount): + if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id { + let peerId = messageId.peerId + if let previousState = updatedState.chatStates[peerId] as? ChannelState { + if previousState.pts >= pts { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old edit update") + } else if previousState.pts + ptsCount == pts { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + var attributes = message.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) + updatedState.editMessage(messageId, message: message.withUpdatedAttributes(attributes)) + updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) + } else { + if !channelsToPoll.contains(peerId) { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) edit message pts hole") + channelsToPoll.insert(peerId) + //updatedMissingUpdates = true + } + } + } else { + if !channelsToPoll.contains(peerId) { + //Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) state unknown") + channelsToPoll.insert(peerId) + } + } + } else { + Logger.shared.log("State", "Invalid updateEditChannelMessage") + } + case let .updateChannelWebPage(channelId, apiWebpage, pts, ptsCount): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if let previousState = updatedState.chatStates[peerId] as? ChannelState { + if previousState.pts >= pts { + } else if previousState.pts + ptsCount == pts { + switch apiWebpage { + case let .webPageEmpty(id): + updatedState.updateMedia(MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), media: nil) + default: + if let webpage = telegramMediaWebpageFromApiWebpage(apiWebpage, url: nil) { + updatedState.updateMedia(webpage.webpageId, media: webpage) + } + } + + updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) + } else { + if !channelsToPoll.contains(peerId) { + Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) updateWebPage pts hole") + channelsToPoll.insert(peerId) + } + } + } else { + if !channelsToPoll.contains(peerId) { + channelsToPoll.insert(peerId) + } + } + case let .updateChannelAvailableMessages(channelId, minId): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + updatedState.updateMinAvailableMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minId)) + case let .updateDeleteMessages(messages, _, _): + updatedState.deleteMessagesWithGlobalIds(messages) + case let .updateEditMessage(apiMessage, _, _): + if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + updatedState.editMessage(messageId, message: message) + for media in message.media { + if let media = media as? TelegramMediaAction { + if case .historyCleared = media.action { + updatedState.readInbox(messageId) + } + } + } + } + case let .updateNewChannelMessage(apiMessage, pts, ptsCount): + if let message = StoreMessage(apiMessage: apiMessage) { + if let previousState = updatedState.chatStates[message.id.peerId] as? ChannelState { + if previousState.pts >= pts { + let messageText: String + if Logger.shared.redactSensitiveData { + messageText = "[[redacted]]" + } else { + messageText = message.text + } + Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) skip old message \(message.id) (\(messageText))") + } else if previousState.pts + ptsCount == pts { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + var attributes = message.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) + updatedState.addMessages([message.withUpdatedAttributes(attributes)], location: .UpperHistoryBlock) + updatedState.updateChannelState(message.id.peerId, state: previousState.withUpdatedPts(pts)) + } else { + if !channelsToPoll.contains(message.id.peerId) { + Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) message pts hole") + ; + channelsToPoll.insert(message.id.peerId) + //updatedMissingUpdates = true + } + } + } else { + if !channelsToPoll.contains(message.id.peerId) { + Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) state unknown") + channelsToPoll.insert(message.id.peerId) + } + } + } + case let .updateNewMessage(apiMessage, _, _): + if let message = StoreMessage(apiMessage: apiMessage) { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + updatedState.addMessages([message], location: .UpperHistoryBlock) + } + case let .updateServiceNotification(_, date, type, text, media, entities): + if let date = date { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 777000) + + if updatedState.peers[peerId] == nil { + updatedState.updatePeer(peerId, { peer in + if peer == nil { + return TelegramUser(id: peerId, accessHash: nil, firstName: "Telegram Notifications", lastName: nil, username: nil, phone: nil, photo: [], botInfo: BotUserInfo(flags: [], inlinePlaceholder: nil), restrictionInfo: nil, flags: [.isVerified]) + } else { + return peer + } + }) + } + + var alreadyStored = false + if let storedMessages = updatedState.storedMessagesByPeerIdAndTimestamp[peerId] { + for index in storedMessages { + if index.timestamp == date { + alreadyStored = true + break + } + } + } + + if alreadyStored { + Logger.shared.log("State", "skipping message at \(date) for \(peerId): already stored") + } else { + var attributes: [MessageAttribute] = [] + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities))) + } + let messageText = text + var medias: [Media] = [] + + let (mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId) + if let mediaValue = mediaValue { + medias.append(mediaValue) + } + if let expirationTimer = expirationTimer { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: expirationTimer, countdownBeginTime: nil)) + } + + let message = StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: peerId, text: messageText, attributes: attributes, media: medias) + updatedState.addMessages([message], location: .UpperHistoryBlock) + } + } else { + updatedState.addDisplayAlert(text, isDropAuth: type.hasPrefix("AUTH_KEY_DROP_")) + } + case let .updateReadChannelInbox(_, folderId, channelId, maxId, stillUnreadCount, pts): + updatedState.resetIncomingReadState(groupId: PeerGroupId(rawValue: folderId ?? 0), peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, maxIncomingReadId: maxId, count: stillUnreadCount, pts: pts) + case let .updateReadChannelOutbox(channelId, maxId): + updatedState.readOutbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId), timestamp: nil) + case let .updateChannel(channelId): + updatedState.addExternallyUpdatedPeerId(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)) + case let .updateReadHistoryInbox(_, folderId, peer, maxId, stillUnreadCount, pts, _): + updatedState.resetIncomingReadState(groupId: PeerGroupId(rawValue: folderId ?? 0), peerId: peer.peerId, namespace: Namespaces.Message.Cloud, maxIncomingReadId: maxId, count: stillUnreadCount, pts: pts) + case let .updateReadHistoryOutbox(peer, maxId, _, _): + updatedState.readOutbox(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: maxId), timestamp: updatesDate) + case let .updateDialogUnreadMark(flags, peer): + switch peer { + case let .dialogPeer(peer): + let peerId = peer.peerId + updatedState.updatePeerChatUnreadMark(peerId, namespace: Namespaces.Message.Cloud, value: (flags & (1 << 0)) != 0) + case .dialogPeerFolder: + break + } + case let .updateWebPage(apiWebpage, _, _): + switch apiWebpage { + case let .webPageEmpty(id): + updatedState.updateMedia(MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), media: nil) + default: + if let webpage = telegramMediaWebpageFromApiWebpage(apiWebpage, url: nil) { + updatedState.updateMedia(webpage.webpageId, media: webpage) + } + } + case let .updateNotifySettings(apiPeer, apiNotificationSettings): + switch apiPeer { + case let .notifyPeer(peer): + let notificationSettings = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) + updatedState.updateNotificationSettings(.peer(peer.peerId), notificationSettings: notificationSettings) + case .notifyUsers: + updatedState.updateGlobalNotificationSettings(.privateChats, notificationSettings: MessageNotificationSettings(apiSettings: apiNotificationSettings)) + case .notifyChats: + updatedState.updateGlobalNotificationSettings(.groups, notificationSettings: MessageNotificationSettings(apiSettings: apiNotificationSettings)) + case .notifyBroadcasts: + updatedState.updateGlobalNotificationSettings(.channels, notificationSettings: MessageNotificationSettings(apiSettings: apiNotificationSettings)) + } + case let .updateChatParticipants(participants): + let groupPeerId: PeerId + switch participants { + case let .chatParticipants(chatId, _, _): + groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .chatParticipantsForbidden(_, chatId, _): + groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + } + updatedState.updateCachedPeerData(groupPeerId, { current in + let previous: CachedGroupData + if let current = current as? CachedGroupData { + previous = current + } else { + previous = CachedGroupData() + } + return previous.withUpdatedParticipants(CachedGroupParticipants(apiParticipants: participants)) + }) + case let .updateChatParticipantAdd(chatId, userId, inviterId, date, _): + let groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + let inviterPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId) + updatedState.updateCachedPeerData(groupPeerId, { current in + if let current = current as? CachedGroupData, let participants = current.participants { + var updatedParticipants = participants.participants + if updatedParticipants.index(where: { $0.peerId == userPeerId }) == nil { + updatedParticipants.append(.member(id: userPeerId, invitedBy: inviterPeerId, invitedAt: date)) + } + return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return current + } + }) + case let .updateChatParticipantDelete(chatId, userId, _): + let groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + updatedState.updateCachedPeerData(groupPeerId, { current in + if let current = current as? CachedGroupData, let participants = current.participants { + var updatedParticipants = participants.participants + if let index = updatedParticipants.index(where: { $0.peerId == userPeerId }) { + updatedParticipants.remove(at: index) + } + return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return current + } + }) + case let .updateChatParticipantAdmin(chatId, userId, isAdmin, _): + let groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + updatedState.updateCachedPeerData(groupPeerId, { current in + if let current = current as? CachedGroupData, let participants = current.participants { + var updatedParticipants = participants.participants + if let index = updatedParticipants.index(where: { $0.peerId == userPeerId }) { + if isAdmin == .boolTrue { + if case let .member(id, invitedBy, invitedAt) = updatedParticipants[index] { + updatedParticipants[index] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt) + } + } else { + if case let .admin(id, invitedBy, invitedAt) = updatedParticipants[index] { + updatedParticipants[index] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt) + } + } + } + return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return current + } + }) + case let .updateChatDefaultBannedRights(peer, defaultBannedRights, version): + updatedState.updatePeer(peer.peerId, { peer in + if let group = peer as? TelegramGroup {//, group.version == version - 1 { + return group.updateDefaultBannedRights(TelegramChatBannedRights(apiBannedRights: defaultBannedRights), version: max(group.version, Int(version))) + } else if let channel = peer as? TelegramChannel {//, group.version == version - 1 { + return channel.withUpdatedDefaultBannedRights(TelegramChatBannedRights(apiBannedRights: defaultBannedRights)) + } else { + return peer + } + }) + case let .updateChannelPinnedMessage(channelId, id): + let channelPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + updatedState.updateCachedPeerData(channelPeerId, { current in + let previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + return previous.withUpdatedPinnedMessageId(id == 0 ? nil : MessageId(peerId: channelPeerId, namespace: Namespaces.Message.Cloud, id: id)) + }) + case let .updateUserPinnedMessage(userId, id): + let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + updatedState.updateCachedPeerData(userPeerId, { current in + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + return previous.withUpdatedPinnedMessageId(id == 0 ? nil : MessageId(peerId: userPeerId, namespace: Namespaces.Message.Cloud, id: id)) + }) + case let .updateChatPinnedMessage(groupId, id, version): + let groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: groupId) + updatedState.updateCachedPeerData(groupPeerId, { current in + let previous: CachedGroupData + if let current = current as? CachedGroupData { + previous = current + } else { + previous = CachedGroupData() + } + return previous.withUpdatedPinnedMessageId(id == 0 ? nil : MessageId(peerId: groupPeerId, namespace: Namespaces.Message.Cloud, id: id)) + }) + case let .updateUserBlocked(userId, blocked): + let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + updatedState.updateCachedPeerData(userPeerId, { current in + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + return previous.withUpdatedIsBlocked(blocked == .boolTrue) + }) + case let .updateUserStatus(userId, status): + updatedState.mergePeerPresences([PeerId(namespace: Namespaces.Peer.CloudUser, id: userId): status], explicit: true) + case let .updateUserName(userId, firstName, lastName, username): + //TODO add contact checking for apply first and last name + updatedState.updatePeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), { peer in + if let user = peer as? TelegramUser { + return user.withUpdatedUsername(username) + } else { + return peer + } + }) + case let .updateUserPhoto(userId, _, photo, _): + updatedState.updatePeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), { peer in + if let user = peer as? TelegramUser { + return user.withUpdatedPhoto(parsedTelegramProfilePhoto(photo)) + } else { + return peer + } + }) + case let .updateUserPhone(userId, phone): + updatedState.updatePeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), { peer in + if let user = peer as? TelegramUser { + return user.withUpdatedPhone(phone.isEmpty ? nil : phone) + } else { + return peer + } + }) + case let .updatePeerSettings(peer, settings): + let peerStatusSettings = PeerStatusSettings(apiSettings: settings) + updatedState.updateCachedPeerData(peer.peerId, { current in + if peer.peerId.namespace == Namespaces.Peer.CloudUser { + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if peer.peerId.namespace == Namespaces.Peer.CloudGroup { + let previous: CachedGroupData + if let current = current as? CachedGroupData { + previous = current + } else { + previous = CachedGroupData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if peer.peerId.namespace == Namespaces.Peer.CloudChannel { + let previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return current + } + }) + case let .updateEncryption(chat, date): + updatedState.updateSecretChat(chat: chat, timestamp: date) + case let .updateNewEncryptedMessage(message, _): + updatedState.addSecretMessages([message]) + case let .updateEncryptedMessagesRead(chatId, maxDate, date): + updatedState.readSecretOutbox(peerId: PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId), timestamp: maxDate, actionTimestamp: date) + case let .updateUserTyping(userId, type): + if let date = updatesDate, date + 60 > serverTime { + updatedState.addPeerInputActivity(chatPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), activity: PeerInputActivity(apiType: type)) + } + case let .updateChatUserTyping(chatId, userId, type): + if let date = updatesDate, date + 60 > serverTime { + updatedState.addPeerInputActivity(chatPeerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), activity: PeerInputActivity(apiType: type)) + updatedState.addPeerInputActivity(chatPeerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: chatId), peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), activity: PeerInputActivity(apiType: type)) + } + case let .updateEncryptedChatTyping(chatId): + if let date = updatesDate, date + 60 > serverTime { + updatedState.addPeerInputActivity(chatPeerId: PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId), peerId: nil, activity: .typingText) + } + case let .updateDialogPinned(flags, folderId, peer): + let groupId: PeerGroupId = folderId.flatMap(PeerGroupId.init(rawValue:)) ?? .root + let item: PinnedItemId + switch peer { + case let .dialogPeer(peer): + item = .peer(peer.peerId) + case .dialogPeerFolder: + preconditionFailure() + } + if (flags & (1 << 0)) != 0 { + updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .pin(item)) + } else { + updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .unpin(item)) + } + case let .updatePinnedDialogs(_, folderId, order): + let groupId: PeerGroupId = folderId.flatMap(PeerGroupId.init(rawValue:)) ?? .root + if let order = order { + updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .reorder(order.map { + let item: PinnedItemId + switch $0 { + case let .dialogPeer(peer): + item = .peer(peer.peerId) + case .dialogPeerFolder: + preconditionFailure() + } + return item + })) + } else { + updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .sync) + } + case let .updateReadMessagesContents(messages, _, _): + updatedState.addReadMessagesContents((nil, messages)) + case let .updateChannelReadMessagesContents(channelId, messages): + updatedState.addReadMessagesContents((PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), messages)) + case let .updateChannelMessageViews(channelId, id, views): + updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: id), count: views) + case let .updateNewStickerSet(stickerset): + updatedState.addUpdateInstalledStickerPacks(.add(stickerset)) + case let .updateStickerSetsOrder(flags, order): + let namespace: SynchronizeInstalledStickerPacksOperationNamespace + if (flags & (1 << 0)) != 0 { + namespace = .masks + } else { + namespace = .stickers + } + updatedState.addUpdateInstalledStickerPacks(.reorder(namespace, order)) + case .updateStickerSets: + updatedState.addUpdateInstalledStickerPacks(.sync) + case .updateSavedGifs: + updatedState.addUpdateRecentGifs() + case let .updateDraftMessage(peer, draft): + let inputState: SynchronizeableChatInputState? + switch draft { + case .draftMessageEmpty: + inputState = nil + case let .draftMessage(_, replyToMsgId, message, entities, date): + var replyToMessageId: MessageId? + if let replyToMsgId = replyToMsgId { + replyToMessageId = MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId) + } + inputState = SynchronizeableChatInputState(replyToMessageId: replyToMessageId, text: message, entities: messageTextEntitiesFromApiEntities(entities ?? []), timestamp: date) + } + updatedState.addUpdateChatInputState(peerId: peer.peerId, state: inputState) + case let .updatePhoneCall(phoneCall): + updatedState.addUpdateCall(phoneCall) + case let .updateLangPackTooLong(langCode): + updatedState.updateLangPack(langCode: langCode, difference: nil) + case let .updateLangPack(difference): + let langCode: String + switch difference { + case let .langPackDifference(langPackDifference): + langCode = langPackDifference.langCode + } + updatedState.updateLangPack(langCode: langCode, difference: difference) + case let .updateMessagePoll(_, pollId, poll, results): + updatedState.updateMessagePoll(MediaId(namespace: Namespaces.Media.CloudPoll, id: pollId), poll: poll, results: results) + case let .updateFolderPeers(folderPeers, _, _): + for folderPeer in folderPeers { + switch folderPeer { + case let .folderPeer(peer, folderId): + updatedState.updatePeerChatInclusion(peerId: peer.peerId, groupId: PeerGroupId(rawValue: folderId), changedGroup: true) + } + } + case let .updateContactLocated(contacts): + var peersNearby: [PeerNearby] = [] + for case let .contactLocated(userId, expires, distance) in contacts { + peersNearby.append(PeerNearby(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), expires: expires, distance: distance)) + } + updatedState.updatePeersNearby(peersNearby) + default: + break + } + } + + var pollChannelSignals: [Signal<(AccountMutableState, Bool, Int32?), NoError>] = [] + if channelsToPoll.isEmpty { + pollChannelSignals = [] + } else if shouldResetChannels { + var channelPeers: [Peer] = [] + for peerId in channelsToPoll { + if let peer = updatedState.peers[peerId] { + channelPeers.append(peer) + } else { + Logger.shared.log("State", "can't reset channel \(peerId): no peer found") + } + } + if !channelPeers.isEmpty { + let resetSignal = resetChannels(network: network, peers: channelPeers, state: updatedState) + |> map { resultState -> (AccountMutableState, Bool, Int32?) in + return (resultState, true, nil) + } + pollChannelSignals = [resetSignal] + } else { + pollChannelSignals = [] + } + } else { + for peerId in channelsToPoll { + if let peer = updatedState.peers[peerId] { + pollChannelSignals.append(pollChannel(network: network, peer: peer, state: updatedState.branch())) + } else { + Logger.shared.log("State", "can't poll channel \(peerId): no peer found") + } + } + } + + return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal in + var finalState: AccountMutableState = updatedState + var hadError = false + + if shouldResetChannels && states.count != 0 { + assert(states.count == 1) + finalState = states[0].0 + } else { + for (state, success, _) in states { + finalState.merge(state) + if !success { + hadError = true + } + } + } + return resolveAssociatedMessages(network: network, state: finalState) + |> mapToSignal { resultingState -> Signal in + return resolveMissingPeerChatInfos(network: network, state: resultingState) + |> map { resultingState -> AccountFinalState in + return AccountFinalState(state: resultingState, shouldPoll: shouldPoll || hadError, incomplete: missingUpdates) + } + } + } +} + + +private func resolveAssociatedMessages(network: Network, state: AccountMutableState) -> Signal { + let missingMessageIds = state.referencedMessageIds.subtracting(state.storedMessages) + if missingMessageIds.isEmpty { + return .single(state) + } else { + var missingPeers = false + + var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] + for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { + if let peer = state.peers[peerId] { + var signal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + signal = network.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } + } + if let signal = signal { + signals.append(signal |> map { result in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, messages, chats, users): + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + }) + } + } else { + missingPeers = true + } + } + + let fetchMessages = combineLatest(signals) + + return fetchMessages |> map { results in + var updatedState = state + for (messages, chats, users) in results { + if !messages.isEmpty { + var storeMessages: [StoreMessage] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message) { + storeMessages.append(message) + } + } + updatedState.addMessages(storeMessages, location: .Random) + } + if !chats.isEmpty { + updatedState.mergeChats(chats) + } + if !users.isEmpty { + updatedState.mergeUsers(users) + } + } + return updatedState + } + } +} + +private func resolveMissingPeerChatInfos(network: Network, state: AccountMutableState) -> Signal { + var missingPeers: [PeerId: Api.InputPeer] = [:] + + for peerId in state.initialState.peerIdsRequiringLocalChatState { + if state.peerChatInfos[peerId] == nil { + if let peer = state.peers[peerId], let inputPeer = apiInputPeer(peer) { + missingPeers[peerId] = inputPeer + } else { + Logger.shared.log("State", "can't fetch chat info for peer \(peerId): can't create inputPeer") + } + } + } + + if missingPeers.isEmpty { + return .single(state) + } else { + Logger.shared.log("State", "will fetch chat info for \(missingPeers.count) peers") + let signal = network.request(Api.functions.messages.getPeerDialogs(peers: missingPeers.values.map(Api.InputDialogPeer.inputDialogPeer(peer:)))) + |> map(Optional.init) + + return signal + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> AccountMutableState in + guard let result = result else { + return state + } + + var channelStates: [PeerId: ChannelState] = [:] + + var updatedState = state + switch result { + case let .peerDialogs(dialogs, messages, chats, users, state): + updatedState.mergeChats(chats) + updatedState.mergeUsers(users) + + var topMessageIds = Set() + + for dialog in dialogs { + switch dialog { + case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, notifySettings, pts, draft, folderId): + let peerId = peer.peerId + + updatedState.setNeedsHoleFromPreviousState(peerId: peerId, namespace: Namespaces.Message.Cloud) + + if topMessage != 0 { + topMessageIds.insert(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: topMessage)) + } + + var isExcludedFromChatList = false + for chat in chats { + if chat.peerId == peerId { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + if let group = groupOrChannel as? TelegramGroup { + if group.flags.contains(.deactivated) { + isExcludedFromChatList = true + } else { + switch group.membership { + case .Member: + break + default: + isExcludedFromChatList = true + } + } + } else if let channel = groupOrChannel as? TelegramChannel { + switch channel.participationStatus { + case .member: + break + default: + isExcludedFromChatList = true + } + } + } + break + } + } + + if !isExcludedFromChatList { + updatedState.updatePeerChatInclusion(peerId: peerId, groupId: PeerGroupId(rawValue: folderId ?? 0), changedGroup: false) + } + + let notificationSettings = TelegramPeerNotificationSettings(apiSettings: notifySettings) + updatedState.updateNotificationSettings(.peer(peer.peerId), notificationSettings: notificationSettings) + + updatedState.resetReadState(peer.peerId, namespace: Namespaces.Message.Cloud, maxIncomingReadId: readInboxMaxId, maxOutgoingReadId: readOutboxMaxId, maxKnownId: topMessage, count: unreadCount, markedUnread: nil) + updatedState.resetMessageTagSummary(peer.peerId, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: topMessage)) + updatedState.peerChatInfos[peer.peerId] = PeerChatInfo(notificationSettings: notificationSettings) + if let pts = pts { + channelStates[peer.peerId] = ChannelState(pts: pts, invalidatedPts: pts) + } + case .dialogFolder: + assertionFailure() + break + } + } + + var storeMessages: [StoreMessage] = [] + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + var updatedStoreMessage = storeMessage + if case let .Id(id) = storeMessage.id { + if let channelState = channelStates[id.peerId] { + var updatedAttributes = storeMessage.attributes + updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) + } + } + storeMessages.append(updatedStoreMessage) + } + } + + for message in storeMessages { + if case let .Id(id) = message.id { + updatedState.addMessages([message], location: topMessageIds.contains(id) ? .UpperHistoryBlock : .Random) + } + } + } + return updatedState + } + } +} + +func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal { + return postbox.transaction { transaction -> Signal in + if let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) { + var chatStates: [PeerId: PeerChatState] = [:] + if let channelState = transaction.getPeerChatState(peerId) as? ChannelState { + chatStates[peerId] = channelState + } + let initialPeers: [PeerId: Peer] = [peerId: peer] + var peerChatInfos: [PeerId: PeerChatInfo] = [:] + let inclusion = transaction.getPeerChatListInclusion(peerId) + var hasValidInclusion = false + switch inclusion { + case .ifHasMessagesOrOneOf: + hasValidInclusion = true + case .notIncluded: + hasValidInclusion = false + } + if hasValidInclusion { + if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings { + peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) + } + } + let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), chatStates: chatStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) + return pollChannel(network: network, peer: peer, state: initialState) + |> mapToSignal { (finalState, _, timeout) -> Signal in + return resolveAssociatedMessages(network: network, state: finalState) + |> mapToSignal { resultingState -> Signal in + return resolveMissingPeerChatInfos(network: network, state: resultingState) + |> map { resultingState -> AccountFinalState in + return AccountFinalState(state: resultingState, shouldPoll: false, incomplete: false) + } + } + |> mapToSignal { finalState -> Signal in + return stateManager.addReplayAsynchronouslyBuiltFinalState(finalState) + |> mapToSignal { _ -> Signal in + return .complete() |> delay(Double(timeout ?? 30), queue: Queue.concurrentDefaultQueue()) + } + } + } + } else { + return .complete() + |> delay(30.0, queue: Queue.concurrentDefaultQueue()) + } + } + |> switchToLatest + |> restart +} + +private func resetChannels(network: Network, peers: [Peer], state: AccountMutableState) -> Signal { + var inputPeers: [Api.InputDialogPeer] = [] + for peer in peers { + if let inputPeer = apiInputPeer(peer) { + inputPeers.append(.inputDialogPeer(peer: inputPeer)) + } + } + return network.request(Api.functions.messages.getPeerDialogs(peers: inputPeers)) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorDescription == "CHANNEL_PRIVATE" && inputPeers.count == 1 { + return .single(nil) + } else { + return .single(nil) + } + } + |> mapToSignal { result -> Signal in + var updatedState = state + + var dialogsChats: [Api.Chat] = [] + var dialogsUsers: [Api.User] = [] + + var storeMessages: [StoreMessage] = [] + var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] + var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] + var channelStates: [PeerId: ChannelState] = [:] + var notificationSettings: [PeerId: PeerNotificationSettings] = [:] + + if let result = result { + switch result { + case let .peerDialogs(dialogs, messages, chats, users, _): + dialogsChats.append(contentsOf: chats) + dialogsUsers.append(contentsOf: users) + + loop: for dialog in dialogs { + let apiPeer: Api.Peer + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiTopMessage: Int32 + let apiUnreadCount: Int32 + let apiUnreadMentionsCount: Int32 + var apiChannelPts: Int32? + let apiNotificationSettings: Api.PeerNotifySettings + let apiMarkedUnread: Bool + let groupId: PeerGroupId + switch dialog { + case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _, folderId): + apiPeer = peer + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + apiUnreadMentionsCount = unreadMentionsCount + apiNotificationSettings = peerNotificationSettings + apiChannelPts = pts + groupId = PeerGroupId(rawValue: folderId ?? 0) + case .dialogFolder: + assertionFailure() + continue loop + } + + let peerId: PeerId + switch apiPeer { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + if readStates[peerId] == nil { + readStates[peerId] = [:] + } + readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) + + if apiTopMessage != 0 { + mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage)) + } + + if let apiChannelPts = apiChannelPts { + channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts) + } + + notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) + + updatedState.updatePeerChatInclusion(peerId: peerId, groupId: groupId, changedGroup: false) + } + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + var updatedStoreMessage = storeMessage + if case let .Id(id) = storeMessage.id { + if let channelState = channelStates[id.peerId] { + var updatedAttributes = storeMessage.attributes + updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) + } + } + storeMessages.append(updatedStoreMessage) + } + } + } + } + + updatedState.mergeChats(dialogsChats) + updatedState.mergeUsers(dialogsUsers) + + for message in storeMessages { + if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud { + updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace) + } + } + + updatedState.addMessages(storeMessages, location: .UpperHistoryBlock) + + for (peerId, peerReadStates) in readStates { + for (namespace, state) in peerReadStates { + switch state { + case let .idBased(maxIncomingReadId, maxOutgoingReadId, maxKnownId, count, markedUnread): + updatedState.resetReadState(peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread) + default: + assertionFailure() + break + } + } + } + + for (peerId, tagSummary) in mentionTagSummaries { + updatedState.resetMessageTagSummary(peerId, namespace: Namespaces.Message.Cloud, count: tagSummary.count, range: tagSummary.range) + } + + for (peerId, channelState) in channelStates { + updatedState.updateChannelState(peerId, state: channelState) + } + + for (peerId, settings) in notificationSettings { + updatedState.updateNotificationSettings(.peer(peerId), notificationSettings: settings) + } + + // TODO: delete messages later than top + + return resolveAssociatedMessages(network: network, state: updatedState) + |> mapToSignal { resultingState -> Signal in + return .single(resultingState) + } + } +} + +private func pollChannel(network: Network, peer: Peer, state: AccountMutableState) -> Signal<(AccountMutableState, Bool, Int32?), NoError> { + if let inputChannel = apiInputChannel(peer) { + let limit: Int32 = 20 + let pollPts: Int32 + if let channelState = state.chatStates[peer.id] as? ChannelState { + pollPts = channelState.pts + } else { + pollPts = 1 + } + return (network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: pollPts, limit: limit)) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorDescription == "CHANNEL_PRIVATE" { + return .single(nil) + } else { + return .fail(error) + } + }) + |> retryRequest + |> map { difference -> (AccountMutableState, Bool, Int32?) in + var updatedState = state + var apiTimeout: Int32? + if let difference = difference { + switch difference { + case let .channelDifference(_, pts, timeout, newMessages, otherUpdates, chats, users): + apiTimeout = timeout + let channelState: ChannelState + if let previousState = updatedState.chatStates[peer.id] as? ChannelState { + channelState = previousState.withUpdatedPts(pts) + } else { + channelState = ChannelState(pts: pts, invalidatedPts: nil) + } + updatedState.updateChannelState(peer.id, state: channelState) + + updatedState.mergeChats(chats) + updatedState.mergeUsers(users) + + for apiMessage in newMessages { + if let message = StoreMessage(apiMessage: apiMessage) { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + updatedState.addMessages([message], location: .UpperHistoryBlock) + } + } + for update in otherUpdates { + switch update { + case let .updateDeleteChannelMessages(_, messages, _, _): + let peerId = peer.id + updatedState.deleteMessages(messages.map({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })) + case let .updateEditChannelMessage(apiMessage, _, _): + if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id, messageId.peerId == peer.id { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + var attributes = message.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) + updatedState.editMessage(messageId, message: message.withUpdatedAttributes(attributes)) + } else { + Logger.shared.log("State", "Invalid updateEditChannelMessage") + } + case let .updateChannelPinnedMessage(_, id): + updatedState.updateCachedPeerData(peer.id, { current in + let previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + return previous.withUpdatedPinnedMessageId(id == 0 ? nil : MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)) + }) + case let .updateChannelReadMessagesContents(_, messages): + updatedState.addReadMessagesContents((peer.id, messages)) + case let .updateChannelMessageViews(_, id, views): + updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views) + case let .updateChannelWebPage(_, apiWebpage, _, _): + switch apiWebpage { + case let .webPageEmpty(id): + updatedState.updateMedia(MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), media: nil) + default: + if let webpage = telegramMediaWebpageFromApiWebpage(apiWebpage, url: nil) { + updatedState.updateMedia(webpage.webpageId, media: webpage) + } + } + case let .updateChannelAvailableMessages(_, minId): + let messageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: minId) + updatedState.updateMinAvailableMessage(messageId) + updatedState.updateCachedPeerData(peer.id, { current in + let previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + return previous.withUpdatedMinAvailableMessageId(messageId) + }) + default: + break + } + } + case let .channelDifferenceEmpty(_, pts, timeout): + apiTimeout = timeout + + let channelState: ChannelState + if let previousState = updatedState.chatStates[peer.id] as? ChannelState { + channelState = previousState.withUpdatedPts(pts) + } else { + channelState = ChannelState(pts: pts, invalidatedPts: nil) + } + updatedState.updateChannelState(peer.id, state: channelState) + case let .channelDifferenceTooLong(_, timeout, dialog, messages, chats, users): + apiTimeout = timeout + + var parameters: (peer: Api.Peer, pts: Int32, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32)? + + switch dialog { + case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, notifySettings, pts, draft, folderId): + if let pts = pts { + parameters = (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount) + } + case .dialogFolder: + break + } + + if let (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount) = parameters { + let channelState = ChannelState(pts: pts, invalidatedPts: pts) + updatedState.updateChannelState(peer.peerId, state: channelState) + + updatedState.mergeChats(chats) + updatedState.mergeUsers(users) + + updatedState.setNeedsHoleFromPreviousState(peerId: peer.peerId, namespace: Namespaces.Message.Cloud) + + for apiMessage in messages { + if let message = StoreMessage(apiMessage: apiMessage) { + if let preCachedResources = apiMessage.preCachedResources { + for (resource, data) in preCachedResources { + updatedState.addPreCachedResource(resource, data: data) + } + } + + let location: AddMessagesLocation + if case let .Id(id) = message.id, id.id == topMessage { + location = .UpperHistoryBlock + } else { + location = .Random + } + updatedState.addMessages([message], location: location) + } + } + + updatedState.resetReadState(peer.peerId, namespace: Namespaces.Message.Cloud, maxIncomingReadId: readInboxMaxId, maxOutgoingReadId: readOutboxMaxId, maxKnownId: topMessage, count: unreadCount, markedUnread: nil) + + updatedState.resetMessageTagSummary(peer.peerId, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: topMessage)) + } else { + assertionFailure() + } + } + } + return (updatedState, difference != nil, apiTimeout) + } + } else { + Logger.shared.log("State", "can't poll channel \(peer.id): can't create inputChannel") + return single((state, true, nil), NoError.self) + } +} + +private func verifyTransaction(_ transaction: Transaction, finalState: AccountMutableState) -> Bool { + var hadUpdateState = false + var channelsWithUpdatedStates = Set() + + var missingPeerIds: [PeerId] = [] + for peerId in finalState.initialState.peerIds { + if finalState.peers[peerId] == nil { + missingPeerIds.append(peerId) + } + } + + if !missingPeerIds.isEmpty { + Logger.shared.log("State", "missing peers \(missingPeerIds)") + return false + } + + for operation in finalState.operations { + switch operation { + case let .UpdateChannelState(peerId, _): + channelsWithUpdatedStates.insert(peerId) + case .UpdateState: + hadUpdateState = true + default: + break + } + } + + var failed = false + + if hadUpdateState { + var previousStateMatches = false + let currentState = (transaction.getState() as? AuthorizedAccountState)?.state + let previousState = finalState.initialState.state + if let currentState = currentState { + previousStateMatches = previousState == currentState + } else { + previousStateMatches = false + } + + if !previousStateMatches { + Logger.shared.log("State", ".UpdateState previous state \(previousState) doesn't match current state \(String(describing: currentState))") + failed = true + } + } + + for peerId in channelsWithUpdatedStates { + let currentState = transaction.getPeerChatState(peerId) + var previousStateMatches = false + let previousState = finalState.initialState.chatStates[peerId] as? ChannelState + if let currentState = currentState, let previousState = previousState { + if currentState.equals(previousState) { + previousStateMatches = true + } + } else if currentState == nil && previousState == nil { + previousStateMatches = true + } + if !previousStateMatches { + Logger.shared.log("State", ".UpdateChannelState for \(peerId), previous state \(String(describing: previousState)) doesn't match current state \(String(describing: currentState))") + failed = true + } + } + + return !failed +} + +private enum ReplayFinalStateIncomplete { + case MoreDataNeeded + case PollRequired +} + +private enum ReplayFinalStateResult { + case Completed + case Incomplete(ReplayFinalStateIncomplete) +} + +private final class OptimizeAddMessagesState { + var messages: [StoreMessage] + var location: AddMessagesLocation + + init(messages: [StoreMessage], location: AddMessagesLocation) { + self.messages = messages + self.location = location + } +} + +private func optimizedOperations(_ operations: [AccountStateMutationOperation]) -> [AccountStateMutationOperation] { + var result: [AccountStateMutationOperation] = [] + + var updatedState: AuthorizedAccountState.State? + var updatedChannelStates: [PeerId: ChannelState] = [:] + + var currentAddMessages: OptimizeAddMessagesState? + for operation in operations { + switch operation { + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby: + if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { + result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) + } + currentAddMessages = nil + result.append(operation) + case let .UpdateState(state): + updatedState = state + case let .UpdateChannelState(peerId, state): + updatedChannelStates[peerId] = state + case let .AddMessages(messages, location): + if let currentAddMessages = currentAddMessages, currentAddMessages.location == location { + currentAddMessages.messages.append(contentsOf: messages) + } else { + if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { + result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) + } + currentAddMessages = OptimizeAddMessagesState(messages: messages, location: location) + } + } + } + if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { + result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) + } + + if let updatedState = updatedState { + result.append(.UpdateState(updatedState)) + } + + for (peerId, state) in updatedChannelStates { + result.append(.UpdateChannelState(peerId, state)) + } + + return result +} + +private func recordPeerActivityTimestamp(peerId: PeerId, timestamp: Int32, into timestamps: inout [PeerId: Int32]) { + if let current = timestamps[peerId] { + if current < timestamp { + timestamps[peerId] = timestamp + } + } else { + timestamps[peerId] = timestamp + } +} + +func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountPeerId: PeerId, mediaBox: MediaBox, transaction: Transaction, auxiliaryMethods: AccountAuxiliaryMethods, finalState: AccountFinalState) -> AccountReplayedFinalState? { + let verified = verifyTransaction(transaction, finalState: finalState.state) + if !verified { + Logger.shared.log("State", "failed to verify final state") + return nil + } + + var peerIdsWithAddedSecretMessages = Set() + + var updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] = [:] + var updatedSecretChatTypingActivities = Set() + var updatedWebpages: [MediaId: TelegramMediaWebpage] = [:] + var updatedCalls: [Api.PhoneCall] = [] + var updatedPeersNearby: [PeerNearby]? + var isContactUpdates: [(PeerId, Bool)] = [] + var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = [] + var recentlyUsedStickers: [MediaId: (MessageIndex, TelegramMediaFile)] = [:] + var recentlyUsedGifs: [MediaId: (MessageIndex, TelegramMediaFile)] = [:] + var syncRecentGifs = false + var langPackDifferences: [String: [Api.LangPackDifference]] = [:] + var pollLangPacks = Set() + var delayNotificatonsUntil: Int32? + var peerActivityTimestamps: [PeerId: Int32] = [:] + + var holesFromPreviousStateMessageIds: [MessageId] = [] + + for (peerId, namespaces) in finalState.state.namespacesWithHolesFromPreviousState { + for namespace in namespaces { + if let id = transaction.getTopPeerMessageId(peerId: peerId, namespace: namespace) { + holesFromPreviousStateMessageIds.append(MessageId(peerId: id.peerId, namespace: id.namespace, id: id.id + 1)) + } else { + holesFromPreviousStateMessageIds.append(MessageId(peerId: peerId, namespace: namespace, id: 1)) + } + } + } + + var addedOperationIncomingMessageIds: [MessageId] = [] + for operation in finalState.state.operations { + switch operation { + case let .AddMessages(messages, location): + if case .UpperHistoryBlock = location { + for message in messages { + if case let .Id(id) = message.id, message.flags.contains(.Incoming) { + addedOperationIncomingMessageIds.append(id) + if let authorId = message.authorId { + recordPeerActivityTimestamp(peerId: authorId, timestamp: message.timestamp, into: &peerActivityTimestamps) + } + } + } + } + default: + break + } + } + var addedIncomingMessageIds: [MessageId] = [] + if !addedOperationIncomingMessageIds.isEmpty { + let existingIds = transaction.filterStoredMessageIds(Set(addedOperationIncomingMessageIds)) + for id in addedOperationIncomingMessageIds { + if !existingIds.contains(id) { + addedIncomingMessageIds.append(id) + } + } + } + + var invalidateGroupStats = Set() + + struct PeerIdAndMessageNamespace: Hashable { + let peerId: PeerId + let namespace: MessageId.Namespace + } + + var topUpperHistoryBlockMessages: [PeerIdAndMessageNamespace: MessageId.Id] = [:] + + for operation in optimizedOperations(finalState.state.operations) { + switch operation { + case let .AddMessages(messages, location): + let _ = transaction.addMessages(messages, location: location) + if case .UpperHistoryBlock = location { + for message in messages { + let chatPeerId = message.id.peerId + if let authorId = message.authorId { + let activityValue: PeerInputActivity? = nil + if updatedTypingActivities[chatPeerId] == nil { + updatedTypingActivities[chatPeerId] = [authorId: activityValue] + } else { + updatedTypingActivities[chatPeerId]![authorId] = activityValue + } + } + + if case let .Id(id) = message.id { + let peerIdAndMessageNamespace = PeerIdAndMessageNamespace(peerId: id.peerId, namespace: id.namespace) + + if let currentId = topUpperHistoryBlockMessages[peerIdAndMessageNamespace] { + if currentId < id.id { + topUpperHistoryBlockMessages[peerIdAndMessageNamespace] = id.id + } + } else { + topUpperHistoryBlockMessages[peerIdAndMessageNamespace] = id.id + } + + for media in message.media { + if let action = media as? TelegramMediaAction { + if message.id.peerId.namespace == Namespaces.Peer.CloudGroup, case let .groupMigratedToChannel(channelId) = action.action { + transaction.updatePeerCachedData(peerIds: [channelId], update: { peerId, current in + var current = current as? CachedChannelData ?? CachedChannelData() + if current.associatedHistoryMessageId == nil { + current = current.withUpdatedMigrationReference(ChannelMigrationReference(maxMessageId: id)) + } + return current + }) + } + switch action.action { + case .groupCreated, .channelMigratedFromGroup: + let holesAtHistoryStart = transaction.getHole(containing: MessageId(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, id: id.id - 1)) + for (space, _) in holesAtHistoryStart { + transaction.removeHole(peerId: chatPeerId, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id) + } + default: + break + } + } + } + } + + if !message.flags.contains(.Incoming), message.forwardInfo == nil { + inner: for media in message.media { + if let file = media as? TelegramMediaFile { + for attribute in file.attributes { + switch attribute { + case .Sticker: + if let index = message.index { + if let (currentIndex, _) = recentlyUsedStickers[file.fileId] { + if currentIndex < index { + recentlyUsedStickers[file.fileId] = (index, file) + } + } else { + recentlyUsedStickers[file.fileId] = (index, file) + } + } + case .Animated: + if let index = message.index { + if let (currentIndex, _) = recentlyUsedGifs[file.fileId] { + if currentIndex < index { + recentlyUsedGifs[file.fileId] = (index, file) + } + } else { + recentlyUsedGifs[file.fileId] = (index, file) + } + } + default: + break + } + } + break inner + } + } + } + } + } + case let .DeleteMessagesWithGlobalIds(ids): + transaction.deleteMessagesWithGlobalIds(ids) + case let .DeleteMessages(ids): + deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids) + case let .UpdateMinAvailableMessage(id): + if let message = transaction.getMessage(id) { + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: id.peerId, minTimestamp: message.timestamp, forceRootGroupIfNotExists: false) + } + transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id) + case let .UpdatePeerChatInclusion(peerId, groupId, changedGroup): + let currentInclusion = transaction.getPeerChatListInclusion(peerId) + var currentPinningIndex: UInt16? + var currentMinTimestamp: Int32? + switch currentInclusion { + case let .ifHasMessagesOrOneOf(currentGroupId, pinningIndex, minTimestamp): + if currentGroupId == groupId { + currentPinningIndex = pinningIndex + } + currentMinTimestamp = minTimestamp + default: + break + } + transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: currentPinningIndex, minTimestamp: currentMinTimestamp)) + if changedGroup { + invalidateGroupStats.insert(Namespaces.PeerGroup.archive) + } + case let .EditMessage(id, message): + transaction.updateMessage(id, update: { previousMessage in + var updatedFlags = message.flags + var updatedLocalTags = message.localTags + if previousMessage.localTags.contains(.OutgoingLiveLocation) { + updatedLocalTags.insert(.OutgoingLiveLocation) + } + if previousMessage.flags.contains(.Incoming) { + updatedFlags.insert(.Incoming) + } else { + updatedFlags.remove(.Incoming) + } + return .update(message.withUpdatedLocalTags(updatedLocalTags).withUpdatedFlags(updatedFlags)) + }) + case let .UpdateMessagePoll(pollId, apiPoll, results): + if let poll = transaction.getMedia(pollId) as? TelegramMediaPoll { + var updatedPoll = poll + if let apiPoll = apiPoll { + switch apiPoll { + case let .poll(id, flags, question, answers): + updatedPoll = TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), text: question, options: answers.map(TelegramMediaPollOption.init(apiOption:)), results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0) + } + } + + let resultsMin: Bool + switch results { + case let .pollResults(pollResults): + resultsMin = (pollResults.flags & (1 << 0)) != 0 + } + updatedPoll = updatedPoll.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin) + updateMessageMedia(transaction: transaction, id: pollId, media: updatedPoll) + } + case let .UpdateMedia(id, media): + if let media = media as? TelegramMediaWebpage { + updatedWebpages[id] = media + } + updateMessageMedia(transaction: transaction, id: id, media: media) + case let .ReadInbox(messageId): + transaction.applyIncomingReadMaxId(messageId) + case let .ReadOutbox(messageId, timestamp): + transaction.applyOutgoingReadMaxId(messageId) + if messageId.peerId != accountPeerId, messageId.peerId.namespace == Namespaces.Peer.CloudUser, let timestamp = timestamp { + recordPeerActivityTimestamp(peerId: messageId.peerId, timestamp: timestamp, into: &peerActivityTimestamps) + } + case let .ReadGroupFeedInbox(groupId, index): + break + //transaction.applyGroupFeedReadMaxIndex(groupId: groupId, index: index) + case let .ResetReadState(peerId, namespace, maxIncomingReadId, maxOutgoingReadId, maxKnownId, count, markedUnread): + var markedUnreadValue: Bool = false + if let markedUnread = markedUnread { + markedUnreadValue = markedUnread + } else if let states = transaction.getPeerReadStates(peerId) { + inner: for (stateNamespace, stateValue) in states { + if stateNamespace == namespace { + markedUnreadValue = stateValue.markedUnread + break inner + } + } + } + transaction.resetIncomingReadStates([peerId: [namespace: .idBased(maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnreadValue)]]) + case let .ResetIncomingReadState(groupId, peerId, namespace, maxIncomingReadId, count, pts): + var ptsMatchesState = false + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + if let state = transaction.getState() as? AuthorizedAccountState { + if state.state?.pts == pts { + ptsMatchesState = true + } + } + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let state = transaction.getPeerChatState(peerId) as? ChannelState { + if state.pts == pts { + ptsMatchesState = true + } + } + } + + if ptsMatchesState { + var updatedStates: [(MessageId.Namespace, PeerReadState)] = transaction.getPeerReadStates(peerId) ?? [] + var foundState = false + for i in 0 ..< updatedStates.count { + if updatedStates[i].0 == namespace { + switch updatedStates[i].1 { + case let .idBased(currentMaxIncomingReadId, maxOutgoingReadId, maxKnownId, _, markedUnread): + updatedStates[i].1 = .idBased(maxIncomingReadId: max(currentMaxIncomingReadId, maxIncomingReadId), maxOutgoingReadId: maxOutgoingReadId, maxKnownId: max(maxKnownId, maxIncomingReadId), count: count, markedUnread: markedUnread) + foundState = true + case .indexBased: + assertionFailure() + break + } + break + } + } + if !foundState { + updatedStates.append((namespace, .idBased(maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxIncomingReadId, maxKnownId: maxIncomingReadId, count: count, markedUnread: false))) + invalidateGroupStats.insert(groupId) + } + let stateDict = Dictionary(updatedStates, uniquingKeysWith: { lhs, _ in lhs }) + transaction.resetIncomingReadStates([peerId: stateDict]) + } else { + transaction.applyIncomingReadMaxId(MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId)) + transaction.setNeedsIncomingReadStateSynchronization(peerId) + invalidateGroupStats.insert(groupId) + } + case let .UpdatePeerChatUnreadMark(peerId, namespace, value): + transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: value, interactive: false) + case let .ResetMessageTagSummary(peerId, namespace, count, range): + transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: namespace, count: count, maxId: range.maxId) + if count == 0 { + transaction.removeHole(peerId: peerId, namespace: namespace, space: .tag(.unseenPersonalMessage), range: 1 ... (Int32.max - 1)) + let ids = transaction.getMessageIndicesWithTag(peerId: peerId, namespace: namespace, tag: .unseenPersonalMessage).map({ $0.id }) + for id in ids { + markUnseenPersonalMessage(transaction: transaction, id: id, addSynchronizeAction: false) + } + } + case let .UpdateState(state): + let currentState = transaction.getState() as! AuthorizedAccountState + transaction.setState(currentState.changedState(state)) + Logger.shared.log("State", "apply state \(state)") + case let .UpdateChannelState(peerId, channelState): + transaction.setPeerChatState(peerId, state: channelState) + Logger.shared.log("State", "apply channel state \(peerId): \(channelState)") + case let .UpdateNotificationSettings(subject, notificationSettings): + switch subject { + case let .peer(peerId): + transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings]) + } + case let .UpdateGlobalNotificationSettings(subject, notificationSettings): + switch subject { + case .privateChats: + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + var updated: GlobalNotificationSettings + if let current = current as? GlobalNotificationSettings { + updated = current + } else { + updated = GlobalNotificationSettings.defaultSettings + } + updated.remote.privateChats = notificationSettings + return updated + }) + case .groups: + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + var updated: GlobalNotificationSettings + if let current = current as? GlobalNotificationSettings { + updated = current + } else { + updated = GlobalNotificationSettings.defaultSettings + } + updated.remote.groupChats = notificationSettings + return updated + }) + case .channels: + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + var updated: GlobalNotificationSettings + if let current = current as? GlobalNotificationSettings { + updated = current + } else { + updated = GlobalNotificationSettings.defaultSettings + } + updated.remote.channels = notificationSettings + return updated + }) + } + case let .MergeApiChats(chats): + var peers: [Peer] = [] + for chat in chats { + if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) { + peers.append(groupOrChannel) + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + case let .MergeApiUsers(users): + var peers: [Peer] = [] + for user in users { + if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers.append(telegramUser) + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + case let .UpdatePeer(id, f): + if let peer = f(transaction.getPeer(id)) { + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in + return updated + }) + } + case let .UpdateCachedPeerData(id, f): + transaction.updatePeerCachedData(peerIds: Set([id]), update: { _, current in + return f(current) + }) + case let .MergePeerPresences(statuses, explicit): + var presences: [PeerId: PeerPresence] = [:] + for (peerId, status) in statuses { + if peerId == accountPeerId { + if explicit { + switch status { + case let .userStatusOnline(timestamp): + delayNotificatonsUntil = timestamp + 30 + case let .userStatusOffline(timestamp): + delayNotificatonsUntil = timestamp + default: + break + } + } + } else { + let presence = TelegramUserPresence(apiStatus: status) + presences[peerId] = presence + } + + } + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences) + case let .UpdateSecretChat(chat, _): + updateSecretChat(accountPeerId: accountPeerId, transaction: transaction, chat: chat, requestData: nil) + case let .AddSecretMessages(messages): + for message in messages { + let peerId = message.peerId + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretIncomingEncrypted, tagLocalIndex: .automatic, tagMergedIndex: .none, contents: SecretChatIncomingEncryptedOperation(message: message)) + peerIdsWithAddedSecretMessages.insert(peerId) + } + case let .ReadSecretOutbox(peerId, maxTimestamp, actionTimestamp): + applyOutgoingReadMaxIndex(transaction: transaction, index: MessageIndex.upperBound(peerId: peerId, timestamp: maxTimestamp, namespace: Namespaces.Message.Local), beginCountdownAt: actionTimestamp) + case let .AddPeerInputActivity(chatPeerId, peerId, activity): + if let peerId = peerId { + if updatedTypingActivities[chatPeerId] == nil { + updatedTypingActivities[chatPeerId] = [peerId: activity] + } else { + updatedTypingActivities[chatPeerId]![peerId] = activity + } + } else if chatPeerId.namespace == Namespaces.Peer.SecretChat { + updatedSecretChatTypingActivities.insert(chatPeerId) + } + case let .UpdatePinnedItemIds(groupId, pinnedOperation): + switch pinnedOperation { + case let .pin(itemId): + switch itemId { + case let .peer(peerId): + if transaction.getPeer(peerId) == nil || transaction.getPeerChatListInclusion(peerId) == .notIncluded { + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + } else { + var currentItemIds = transaction.getPinnedItemIds(groupId: groupId) + if !currentItemIds.contains(.peer(peerId)) { + currentItemIds.insert(.peer(peerId), at: 0) + transaction.setPinnedItemIds(groupId: groupId, itemIds: currentItemIds) + } + } + } + case let .unpin(itemId): + switch itemId { + case let .peer(peerId): + var currentItemIds = transaction.getPinnedItemIds(groupId: groupId) + if let index = currentItemIds.index(of: .peer(peerId)) { + currentItemIds.remove(at: index) + transaction.setPinnedItemIds(groupId: groupId, itemIds: currentItemIds) + } else { + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + } + } + case let .reorder(itemIds): + let currentItemIds = transaction.getPinnedItemIds(groupId: groupId) + if Set(itemIds) == Set(currentItemIds) { + transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds) + } else { + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + } + case .sync: + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + } + case let .ReadMessageContents(peerId, messageIds): + if let peerId = peerId { + for id in messageIds { + markMessageContentAsConsumedRemotely(transaction: transaction, messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id)) + } + } else { + for messageId in transaction.messageIdsForGlobalIds(messageIds) { + markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId) + } + } + case let .UpdateMessageImpressionCount(id, count): + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ViewCountMessageAttribute { + attributes[j] = ViewCountMessageAttribute(count: max(attribute.count, Int(count))) + break loop + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + case let .UpdateInstalledStickerPacks(operation): + stickerPackOperations.append(operation) + case .UpdateRecentGifs: + syncRecentGifs = true + case let .UpdateChatInputState(peerId, inputState): + transaction.updatePeerChatInterfaceState(peerId, update: { current in + return auxiliaryMethods.updatePeerChatInputState(current, inputState) + }) + case let .UpdateCall(call): + updatedCalls.append(call) + case let .UpdateLangPack(langCode, difference): + if let difference = difference { + if langPackDifferences[langCode] == nil { + langPackDifferences[langCode] = [] + } + langPackDifferences[langCode]!.append(difference) + } else { + pollLangPacks.insert(langCode) + } + case let .UpdateIsContact(peerId, value): + isContactUpdates.append((peerId, value)) + case let .UpdatePeersNearby(peersNearby): + updatedPeersNearby = peersNearby + } + } + + for messageId in holesFromPreviousStateMessageIds { + let upperId: MessageId.Id + if let value = topUpperHistoryBlockMessages[PeerIdAndMessageNamespace(peerId: messageId.peerId, namespace: messageId.namespace)], value < Int32.max { + upperId = value - 1 + } else { + upperId = Int32.max + } + if upperId >= messageId.id { + transaction.addHole(peerId: messageId.peerId, namespace: messageId.namespace, space: .everywhere, range: messageId.id ... upperId) + Logger.shared.log("State", "adding hole for peer \(messageId.peerId), \(messageId.id) ... \(upperId)") + } else { + Logger.shared.log("State", "not adding hole for peer \(messageId.peerId), \(upperId) >= \(messageId.id) = false") + } + } + + if !peerActivityTimestamps.isEmpty { + updatePeerPresenceLastActivities(transaction: transaction, accountPeerId: accountPeerId, activities: peerActivityTimestamps) + } + + if !stickerPackOperations.isEmpty { + if stickerPackOperations.contains(where: { + if case .sync = $0 { + return true + } else { + return false + } + }) { + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .stickers, content: .sync) + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .masks, content: .sync) + } else { + var syncStickers = false + var syncMasks = false + loop: for operation in stickerPackOperations { + switch operation { + case let .add(apiSet): + let namespace: ItemCollectionId.Namespace + var items: [ItemCollectionItem] = [] + let info: StickerPackCollectionInfo + switch apiSet { + case let .stickerSet(set, packs, documents): + var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + let key = ValueBoxKey(text).toMemoryBuffer() + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if indexKeysByFile[mediaId] == nil { + indexKeysByFile[mediaId] = [key] + } else { + indexKeysByFile[mediaId]!.append(key) + } + } + break + } + } + + for apiDocument in documents { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + let fileIndexKeys: [MemoryBuffer] + if let indexKeys = indexKeysByFile[id] { + fileIndexKeys = indexKeys + } else { + fileIndexKeys = [] + } + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys)) + } + } + + switch set { + case let .stickerSet(flags, _, _, _, _, _, _, _, _, _): + if (flags & (1 << 3)) != 0 { + namespace = Namespaces.ItemCollection.CloudMaskPacks + } else { + namespace = Namespaces.ItemCollection.CloudStickerPacks + } + } + + info = StickerPackCollectionInfo(apiSet: set, namespace: namespace) + } + + if namespace == Namespaces.ItemCollection.CloudMaskPacks && syncMasks { + continue loop + } else if namespace == Namespaces.ItemCollection.CloudStickerPacks && syncStickers { + continue loop + } + + var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! StickerPackCollectionInfo } + if let index = updatedInfos.index(where: { $0.id == info.id }) { + let currentInfo = updatedInfos[index] + updatedInfos.remove(at: index) + updatedInfos.insert(currentInfo, at: 0) + } else { + updatedInfos.insert(info, at: 0) + transaction.replaceItemCollectionItems(collectionId: info.id, items: items) + } + transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) }) + case let .reorder(namespace, ids): + let collectionNamespace: ItemCollectionId.Namespace + switch namespace { + case .stickers: + collectionNamespace = Namespaces.ItemCollection.CloudStickerPacks + case .masks: + collectionNamespace = Namespaces.ItemCollection.CloudMaskPacks + } + let currentInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo } + if Set(currentInfos.map { $0.id.id }) != Set(ids) { + switch namespace { + case .stickers: + syncStickers = true + case .masks: + syncMasks = true + } + } else { + var currentDict: [ItemCollectionId: StickerPackCollectionInfo] = [:] + for info in currentInfos { + currentDict[info.id] = info + } + var updatedInfos: [StickerPackCollectionInfo] = [] + for id in ids { + let currentInfo = currentDict[ItemCollectionId(namespace: collectionNamespace, id: id)]! + updatedInfos.append(currentInfo) + } + transaction.replaceItemCollectionInfos(namespace: collectionNamespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) }) + } + case .sync: + syncStickers = true + syncMasks = true + break loop + } + } + if syncStickers { + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .stickers, content: .sync) + } + if syncMasks { + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .masks, content: .sync) + } + } + } + + if !recentlyUsedStickers.isEmpty { + let stickerFiles: [TelegramMediaFile] = recentlyUsedStickers.values.sorted(by: { + return $0.0 < $1.0 + }).map({ $0.1 }) + for file in stickerFiles { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + } + } + + if syncRecentGifs { + addSynchronizeSavedGifsOperation(transaction: transaction, operation: .sync) + } else { + let gifFiles: [TelegramMediaFile] = recentlyUsedGifs.values.sorted(by: { + return $0.0 < $1.0 + }).map({ $0.1 }) + for file in gifFiles { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + } + } + + for groupId in invalidateGroupStats { + transaction.setNeedsPeerGroupMessageStatsSynchronization(groupId: groupId, namespace: Namespaces.Message.Cloud) + } + + for chatPeerId in updatedSecretChatTypingActivities { + if let peer = transaction.getPeer(chatPeerId) as? TelegramSecretChat { + let authorId = peer.regularPeerId + let activityValue: PeerInputActivity? = .typingText + if updatedTypingActivities[chatPeerId] == nil { + updatedTypingActivities[chatPeerId] = [authorId: activityValue] + } else { + updatedTypingActivities[chatPeerId]![authorId] = activityValue + } + } + } + + var addedSecretMessageIds: [MessageId] = [] + var addedSecretMessageAuthorIds: [PeerId: PeerId] = [:] + + for peerId in peerIdsWithAddedSecretMessages { + inner: while true { + let keychain = (transaction.getPeerChatState(peerId) as? SecretChatState)?.keychain + if processSecretChatIncomingEncryptedOperations(transaction: transaction, peerId: peerId) { + let processResult = processSecretChatIncomingDecryptedOperations(mediaBox: mediaBox, transaction: transaction, peerId: peerId) + if !processResult.addedMessages.isEmpty { + let currentInclusion = transaction.getPeerChatListInclusion(peerId) + if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive { + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + if let notificationSettings = transaction.getPeerNotificationSettings(peer.regularPeerId) as? TelegramPeerNotificationSettings, !notificationSettings.isRemovedFromTotalUnreadCount { + transaction.updatePeerChatListInclusion(peerId, inclusion: currentInclusion.withGroupId(groupId: .root)) + } + } + } + for message in processResult.addedMessages { + if case let .Id(id) = message.id { + addedSecretMessageIds.append(id) + if let authorId = message.authorId { + if addedSecretMessageAuthorIds[peerId] == nil { + addedSecretMessageAuthorIds[peerId] = authorId + } + } + } + } + } + } + let updatedKeychain = (transaction.getPeerChatState(peerId) as? SecretChatState)?.keychain + if updatedKeychain == keychain { + break inner + } + } + } + + for (chatPeerId, authorId) in addedSecretMessageAuthorIds { + let activityValue: PeerInputActivity? = nil + if updatedTypingActivities[chatPeerId] == nil { + updatedTypingActivities[chatPeerId] = [authorId: activityValue] + } else { + updatedTypingActivities[chatPeerId]![authorId] = activityValue + } + } + + if !pollLangPacks.isEmpty { + addSynchronizeLocalizationUpdatesOperation(transaction: transaction) + } else { + let _ = (accountManager.transaction { transaction -> Void in + outer: for (langCode, langPackDifference) in langPackDifferences { + if !langPackDifference.isEmpty { + let sortedLangPackDifference = langPackDifference.sorted(by: { lhs, rhs in + let lhsVersion: Int32 + switch lhs { + case let .langPackDifference(_, fromVersion, _, _): + lhsVersion = fromVersion + } + let rhsVersion: Int32 + switch rhs { + case let .langPackDifference(_, fromVersion, _, _): + rhsVersion = fromVersion + } + return lhsVersion < rhsVersion + }) + + for difference in sortedLangPackDifference { + if !tryApplyingLanguageDifference(transaction: transaction, langCode: langCode, difference: difference) { + let _ = (postbox.transaction { transaction -> Void in + addSynchronizeLocalizationUpdatesOperation(transaction: transaction) + }).start() + break outer + } + } + } + } + }).start() + } + + addedIncomingMessageIds.append(contentsOf: addedSecretMessageIds) + + return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil) +} diff --git a/submodules/TelegramCore/TelegramCore/AccountStateManager.swift b/submodules/TelegramCore/TelegramCore/AccountStateManager.swift new file mode 100644 index 0000000000..95e885b754 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountStateManager.swift @@ -0,0 +1,1089 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private enum AccountStateManagerOperationContent { + case pollDifference(AccountFinalStateEvents) + case collectUpdateGroups([UpdateGroup], Double) + case processUpdateGroups([UpdateGroup]) + case custom(Int32, Signal) + case pollCompletion(Int32, [MessageId], [(Int32, ([MessageId]) -> Void)]) + case processEvents(Int32, AccountFinalStateEvents) + case replayAsynchronouslyBuiltFinalState(AccountFinalState, () -> Void) +} + +private final class AccountStateManagerOperation { + var isRunning: Bool = false + let content: AccountStateManagerOperationContent + + init(content: AccountStateManagerOperationContent) { + self.content = content + } +} + +private enum AccountStateManagerAddOperationPosition { + case first + case last +} + +#if os(macOS) + private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else + private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private enum CustomOperationEvent { + case Next(T) + case Error(E) + case Completion +} + +private final class UpdatedWebpageSubscriberContext { + let subscribers = Bag<(TelegramMediaWebpage) -> Void>() +} + +private final class UpdatedPeersNearbySubscriberContext { + let subscribers = Bag<([PeerNearby]) -> Void>() +} + +public final class AccountStateManager { + private let queue = Queue() + private let accountPeerId: PeerId + private let accountManager: AccountManager + private let postbox: Postbox + private let network: Network + private let callSessionManager: CallSessionManager + private let addIsContactUpdates: ([(PeerId, Bool)]) -> Void + private let shouldKeepOnlinePresence: Signal + + private let peerInputActivityManager: PeerInputActivityManager + private let auxiliaryMethods: AccountAuxiliaryMethods + + private var updateService: UpdateMessageService? + private let updateServiceDisposable = MetaDisposable() + + private var operations_: [AccountStateManagerOperation] = [] + private var operations: [AccountStateManagerOperation] { + get { + assert(self.queue.isCurrent()) + return self.operations_ + } set(value) { + assert(self.queue.isCurrent()) + self.operations_ = value + } + } + private let operationDisposable = MetaDisposable() + private var operationTimer: SignalKitTimer? + + private var nextId: Int32 = 0 + private func getNextId() -> Int32 { + self.nextId += 1 + return self.nextId + } + + private let isUpdatingValue = ValuePromise(false) + private var currentIsUpdatingValue = false { + didSet { + if self.currentIsUpdatingValue != oldValue { + self.isUpdatingValue.set(self.currentIsUpdatingValue) + } + } + } + public var isUpdating: Signal { + return self.isUpdatingValue.get() + } + + private let notificationMessagesPipe = ValuePipe<[([Message], PeerGroupId, Bool)]>() + public var notificationMessages: Signal<[([Message], PeerGroupId, Bool)], NoError> { + return self.notificationMessagesPipe.signal() + } + + private let displayAlertsPipe = ValuePipe<[(text: String, isDropAuth: Bool)]>() + public var displayAlerts: Signal<[(text: String, isDropAuth: Bool)], NoError> { + return self.displayAlertsPipe.signal() + } + + private let externallyUpdatedPeerIdsPipe = ValuePipe<[PeerId]>() + var externallyUpdatedPeerIds: Signal<[PeerId], NoError> { + return self.externallyUpdatedPeerIdsPipe.signal() + } + + private let termsOfServiceUpdateValue = Atomic(value: nil) + private let termsOfServiceUpdatePromise = Promise(nil) + public var termsOfServiceUpdate: Signal { + return self.termsOfServiceUpdatePromise.get() + } + + private let appliedIncomingReadMessagesPipe = ValuePipe<[MessageId]>() + public var appliedIncomingReadMessages: Signal<[MessageId], NoError> { + return self.appliedIncomingReadMessagesPipe.signal() + } + + private let significantStateUpdateCompletedPipe = ValuePipe() + var significantStateUpdateCompleted: Signal { + return self.significantStateUpdateCompletedPipe.signal() + } + + private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] + private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() + + private let delayNotificatonsUntil = Atomic(value: nil) + private let appliedMaxMessageIdPromise = Promise(nil) + private let appliedMaxMessageIdDisposable = MetaDisposable() + private let appliedQtsPromise = Promise(nil) + private let appliedQtsDisposable = MetaDisposable() + + init(accountPeerId: PeerId, accountManager: AccountManager, postbox: Postbox, network: Network, callSessionManager: CallSessionManager, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal, peerInputActivityManager: PeerInputActivityManager, auxiliaryMethods: AccountAuxiliaryMethods) { + self.accountPeerId = accountPeerId + self.accountManager = accountManager + self.postbox = postbox + self.network = network + self.callSessionManager = callSessionManager + self.addIsContactUpdates = addIsContactUpdates + self.shouldKeepOnlinePresence = shouldKeepOnlinePresence + self.peerInputActivityManager = peerInputActivityManager + self.auxiliaryMethods = auxiliaryMethods + } + + deinit { + self.updateServiceDisposable.dispose() + self.operationDisposable.dispose() + self.appliedMaxMessageIdDisposable.dispose() + self.appliedQtsDisposable.dispose() + } + + func reset() { + self.queue.async { + if self.updateService == nil { + self.updateService = UpdateMessageService(peerId: self.accountPeerId) + self.updateServiceDisposable.set(self.updateService!.pipe.signal().start(next: { [weak self] groups in + if let strongSelf = self { + strongSelf.addUpdateGroups(groups) + } + })) + self.network.mtProto.add(self.updateService) + } + self.operationDisposable.set(nil) + self.replaceOperations(with: .pollDifference(AccountFinalStateEvents())) + self.startFirstOperation() + + let appliedValues: [(MetaDisposable, Signal, Bool)] = [ + (self.appliedMaxMessageIdDisposable, self.appliedMaxMessageIdPromise.get(), true), + (self.appliedQtsDisposable, self.appliedQtsPromise.get(), false) + ] + + for (disposable, value, isMaxMessageId) in appliedValues { + let network = self.network + disposable.set((combineLatest(queue: self.queue, self.shouldKeepOnlinePresence, value) + |> mapToSignal { shouldKeepOnlinePresence, value -> Signal in + guard let value = value else { + return .complete() + } + if !shouldKeepOnlinePresence { + return .complete() + } + return .single(value) + } + |> distinctUntilChanged + |> mapToSignal { value -> Signal in + if isMaxMessageId { + return network.request(Api.functions.messages.receivedMessages(maxId: value)) + |> ignoreValues + |> `catch` { _ -> Signal in + return .complete() + } + } else { + if value == 0 { + return .complete() + } else { + return network.request(Api.functions.messages.receivedQueue(maxQts: value)) + |> ignoreValues + |> `catch` { _ -> Signal in + return .complete() + } + } + } + }).start()) + } + } + } + + func addUpdates(_ updates: Api.Updates) { + self.queue.async { + self.updateService?.addUpdates(updates) + } + } + + func addUpdateGroups(_ groups: [UpdateGroup]) { + self.queue.async { + if let last = self.operations.last { + switch last.content { + case .pollDifference, .processUpdateGroups, .custom, .pollCompletion, .processEvents, .replayAsynchronouslyBuiltFinalState: + self.addOperation(.collectUpdateGroups(groups, 0.0), position: .last) + case let .collectUpdateGroups(currentGroups, timeout): + let operation = AccountStateManagerOperation(content: .collectUpdateGroups(currentGroups + groups, timeout)) + operation.isRunning = last.isRunning + self.operations[self.operations.count - 1] = operation + self.startFirstOperation() + } + } else { + self.addOperation(.collectUpdateGroups(groups, 0.0), position: .last) + } + } + } + + func addReplayAsynchronouslyBuiltFinalState(_ finalState: AccountFinalState) -> Signal { + return Signal { subscriber in + self.queue.async { + self.addOperation(.replayAsynchronouslyBuiltFinalState(finalState, { + subscriber.putNext(true) + subscriber.putCompletion() + }), position: .last) + } + return EmptyDisposable + } + } + + func addCustomOperation(_ f: Signal) -> Signal { + let pipe = ValuePipe>() + return Signal { subscriber in + let disposable = pipe.signal().start(next: { event in + switch event { + case let .Next(next): + subscriber.putNext(next) + case let .Error(error): + subscriber.putError(error) + case .Completion: + subscriber.putCompletion() + } + }) + + let signal = Signal { subscriber in + return f.start(next: { next in + pipe.putNext(.Next(next)) + }, error: { error in + pipe.putNext(.Error(error)) + subscriber.putCompletion() + }, completed: { + pipe.putNext(.Completion) + subscriber.putCompletion() + }) + } + + self.addOperation(.custom(self.getNextId(), signal), position: .last) + + return disposable + } |> runOn(self.queue) + } + + private func replaceOperations(with content: AccountStateManagerOperationContent) { + var collectedProcessUpdateGroups: [AccountStateManagerOperationContent] = [] + var collectedMessageIds: [MessageId] = [] + var collectedPollCompletionSubscribers: [(Int32, ([MessageId]) -> Void)] = [] + var collectedReplayAsynchronouslyBuiltFinalState: [(AccountFinalState, () -> Void)] = [] + var processEvents: [(Int32, AccountFinalStateEvents)] = [] + + var replacedOperations: [AccountStateManagerOperation] = [] + + for i in 0 ..< self.operations.count { + if self.operations[i].isRunning { + replacedOperations.append(self.operations[i]) + } else { + switch self.operations[i].content { + case .processUpdateGroups: + collectedProcessUpdateGroups.append(self.operations[i].content) + case let .pollCompletion(_, messageIds, subscribers): + collectedMessageIds.append(contentsOf: messageIds) + collectedPollCompletionSubscribers.append(contentsOf: subscribers) + case let .replayAsynchronouslyBuiltFinalState(finalState, completion): + collectedReplayAsynchronouslyBuiltFinalState.append((finalState, completion)) + case let .processEvents(operationId, events): + processEvents.append((operationId, events)) + default: + break + } + } + } + + replacedOperations.append(contentsOf: collectedProcessUpdateGroups.map { AccountStateManagerOperation(content: $0) }) + + replacedOperations.append(AccountStateManagerOperation(content: content)) + + if !collectedPollCompletionSubscribers.isEmpty || !collectedMessageIds.isEmpty { + replacedOperations.append(AccountStateManagerOperation(content: .pollCompletion(self.getNextId(), collectedMessageIds, collectedPollCompletionSubscribers))) + } + + for (finalState, completion) in collectedReplayAsynchronouslyBuiltFinalState { + replacedOperations.append(AccountStateManagerOperation(content: .replayAsynchronouslyBuiltFinalState(finalState, completion))) + } + + for (operationId, events) in processEvents { + replacedOperations.append(AccountStateManagerOperation(content: .processEvents(operationId, events))) + } + + self.operations.removeAll() + self.operations.append(contentsOf: replacedOperations) + } + + private func addOperation(_ content: AccountStateManagerOperationContent, position: AccountStateManagerAddOperationPosition) { + self.queue.async { + let operation = AccountStateManagerOperation(content: content) + switch position { + case .first: + if self.operations.isEmpty || !self.operations[0].isRunning { + self.operations.insert(operation, at: 0) + self.startFirstOperation() + } else { + self.operations.insert(operation, at: 1) + } + case .last: + let begin = self.operations.isEmpty + self.operations.append(operation) + if begin { + self.startFirstOperation() + } + } + } + } + + private func startFirstOperation() { + guard let operation = self.operations.first else { + return + } + guard !operation.isRunning else { + return + } + operation.isRunning = true + switch operation.content { + case let .pollDifference(currentEvents): + self.operationTimer?.invalidate() + self.currentIsUpdatingValue = true + let accountManager = self.accountManager + let postbox = self.postbox + let network = self.network + let mediaBox = postbox.mediaBox + let accountPeerId = self.accountPeerId + let auxiliaryMethods = self.auxiliaryMethods + let signal = postbox.stateView() + |> mapToSignal { view -> Signal in + if let state = view.state as? AuthorizedAccountState { + return .single(state) + } else { + return .complete() + } + } + |> take(1) + |> mapToSignal { state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if let authorizedState = state.state { + var flags: Int32 = 0 + var ptsTotalLimit: Int32? = nil + #if DEBUG + //flags = 1 << 0 + //ptsTotalLimit = 1000 + #endif + let request = network.request(Api.functions.updates.getDifference(flags: flags, pts: authorizedState.pts, ptsTotalLimit: ptsTotalLimit, date: authorizedState.date, qts: authorizedState.qts)) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorCode == 406 && error.errorDescription == "AUTH_KEY_DUPLICATED" { + return .single(nil) + } else { + return .fail(error) + } + } + |> retryRequest + + return request + |> mapToSignal { difference -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + guard let difference = difference else { + return .single((nil, nil, true)) + } + switch difference { + case .differenceTooLong: + preconditionFailure() + /*return accountStateReset(postbox: postbox, network: network, accountPeerId: accountPeerId) |> mapToSignal { _ -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in + return .complete() + } + |> then(.single((nil, nil)))*/ + default: + return initialStateWithDifference(postbox: postbox, difference: difference) + |> mapToSignal { state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if state.initialState.state != authorizedState { + Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)") + return .single((nil, nil, false)) + } else { + return finalStateWithDifference(postbox: postbox, network: network, state: state, difference: difference) + |> mapToSignal { finalState -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if !finalState.state.preCachedResources.isEmpty { + for (resource, data) in finalState.state.preCachedResources { + mediaBox.storeResourceData(resource.id, data: data) + } + } + return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in + let startTime = CFAbsoluteTimeGetCurrent() + let replayedState = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime + if deltaTime > 1.0 { + Logger.shared.log("State", "replayFinalState took \(deltaTime)s") + } + + if let replayedState = replayedState { + return (difference, replayedState, false) + } else { + return (nil, nil, false) + } + } + } + } + } + } + } + } else { + let appliedState = network.request(Api.functions.updates.getState()) + |> retryRequest + |> mapToSignal { state in + return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in + if let currentState = transaction.getState() as? AuthorizedAccountState { + switch state { + case let .state(pts, qts, date, seq, _): + transaction.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq))) + } + } + return (nil, nil, false) + } + } + return appliedState + } + } + |> deliverOn(self.queue) + let _ = signal.start(next: { [weak self] difference, finalState, skipBecauseOfError in + if let strongSelf = self { + if case .pollDifference = strongSelf.operations.removeFirst().content { + let events: AccountFinalStateEvents + if let finalState = finalState { + events = currentEvents.union(with: AccountFinalStateEvents(state: finalState)) + } else { + events = currentEvents + } + if let difference = difference { + switch difference { + case .differenceSlice: + strongSelf.addOperation(.pollDifference(events), position: .first) + default: + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + strongSelf.currentIsUpdatingValue = false + strongSelf.significantStateUpdateCompletedPipe.putNext(Void()) + } + } else if skipBecauseOfError { + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + } else { + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + strongSelf.replaceOperations(with: .pollDifference(AccountFinalStateEvents())) + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + }, error: { _ in + assertionFailure() + Logger.shared.log("AccountStateManager", "processUpdateGroups signal completed with error") + }) + case let .collectUpdateGroups(_, timeout): + self.operationTimer?.invalidate() + let operationTimer = SignalKitTimer(timeout: timeout, repeat: false, completion: { [weak self] in + if let strongSelf = self { + let firstOperation = strongSelf.operations.removeFirst() + if case let .collectUpdateGroups(groups, _) = firstOperation.content { + if timeout.isEqual(to: 0.0) { + strongSelf.addOperation(.processUpdateGroups(groups), position: .first) + } else { + Logger.shared.log("AccountStateManager", "timeout while waiting for updates") + strongSelf.replaceOperations(with: .pollDifference(AccountFinalStateEvents())) + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + }, queue: self.queue) + self.operationTimer = operationTimer + operationTimer.start() + case let .processUpdateGroups(groups): + self.operationTimer?.invalidate() + let accountManager = self.accountManager + let postbox = self.postbox + let network = self.network + let auxiliaryMethods = self.auxiliaryMethods + let accountPeerId = self.accountPeerId + let mediaBox = postbox.mediaBox + let queue = self.queue + let signal = initialStateWithUpdateGroups(postbox: postbox, groups: groups) + |> mapToSignal { state -> Signal<(AccountReplayedFinalState?, AccountFinalState), NoError> in + return finalStateWithUpdateGroups(postbox: postbox, network: network, state: state, groups: groups) + |> mapToSignal { finalState in + if !finalState.state.preCachedResources.isEmpty { + for (resource, data) in finalState.state.preCachedResources { + postbox.mediaBox.storeResourceData(resource.id, data: data) + } + } + + return postbox.transaction { transaction -> AccountReplayedFinalState? in + let startTime = CFAbsoluteTimeGetCurrent() + let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime + if deltaTime > 1.0 { + Logger.shared.log("State", "replayFinalState took \(deltaTime)s") + } + return result + } + |> map({ ($0, finalState) }) + |> deliverOn(queue) + } + } + let _ = signal.start(next: { [weak self] replayedState, finalState in + if let strongSelf = self { + if case let .processUpdateGroups(groups) = strongSelf.operations.removeFirst().content { + if let replayedState = replayedState, !finalState.shouldPoll { + let events = AccountFinalStateEvents(state: replayedState) + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + if finalState.incomplete { + strongSelf.addOperation(.collectUpdateGroups(groups, 2.0), position: .last) + } + } else { + if let replayedState = replayedState { + let events = AccountFinalStateEvents(state: replayedState) + if !events.displayAlerts.isEmpty { + strongSelf.insertProcessEvents(AccountFinalStateEvents(displayAlerts: events.displayAlerts)) + } + } + strongSelf.replaceOperations(with: .pollDifference(AccountFinalStateEvents())) + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + }, error: { _ in + assertionFailure() + Logger.shared.log("AccountStateManager", "processUpdateGroups signal completed with error") + }) + case let .custom(operationId, signal): + self.operationTimer?.invalidate() + let completed: () -> Void = { [weak self] in + if let strongSelf = self { + let topOperation = strongSelf.operations.removeFirst() + if case .custom(operationId, _) = topOperation.content { + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + } + let _ = (signal |> deliverOn(self.queue)).start(error: { _ in + completed() + }, completed: { + completed() + }) + case let .processEvents(operationId, events): + self.operationTimer?.invalidate() + let completed: () -> Void = { [weak self] in + if let strongSelf = self { + let topOperation = strongSelf.operations.removeFirst() + if case .processEvents(operationId, _) = topOperation.content { + if !events.updatedTypingActivities.isEmpty { + strongSelf.peerInputActivityManager.transaction { manager in + for (chatPeerId, peerActivities) in events.updatedTypingActivities { + for (peerId, activity) in peerActivities { + if let activity = activity { + manager.addActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity) + } else { + manager.removeAllActivities(chatPeerId: chatPeerId, peerId: peerId) + } + } + } + } + } + if !events.updatedWebpages.isEmpty { + strongSelf.notifyUpdatedWebpages(events.updatedWebpages) + } + if let updatedPeersNearby = events.updatedPeersNearby { + strongSelf.notifyUpdatedPeersNearby(updatedPeersNearby) + } + if !events.updatedCalls.isEmpty { + for call in events.updatedCalls { + strongSelf.callSessionManager.updateSession(call) + } + } + if !events.isContactUpdates.isEmpty { + strongSelf.addIsContactUpdates(events.isContactUpdates) + } + if let updatedMaxMessageId = events.updatedMaxMessageId { + strongSelf.appliedMaxMessageIdPromise.set(.single(updatedMaxMessageId)) + } + if let updatedQts = events.updatedQts { + strongSelf.appliedQtsPromise.set(.single(updatedQts)) + } + var pollCount = 0 + for i in 0 ..< strongSelf.operations.count { + if case let .pollCompletion(pollId, messageIds, subscribers) = strongSelf.operations[i].content { + pollCount += 1 + var updatedMessageIds = messageIds + updatedMessageIds.append(contentsOf: events.addedIncomingMessageIds) + let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, updatedMessageIds, subscribers)) + operation.isRunning = strongSelf.operations[i].isRunning + strongSelf.operations[i] = operation + } + } + assert(pollCount <= 1) + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + } + + if events.delayNotificatonsUntil != nil { + let _ = self.delayNotificatonsUntil.swap(events.delayNotificatonsUntil) + } + + let signal = self.postbox.transaction { transaction -> [([Message], PeerGroupId, Bool)] in + var messageList: [([Message], PeerGroupId, Bool)] = [] + for id in events.addedIncomingMessageIds { + let (messages, notify, _, _) = messagesForNotification(transaction: transaction, id: id, alwaysReturnMessage: false) + if !messages.isEmpty { + messageList.append((messages, .root, notify)) + } + } + return messageList + } + + let _ = (signal + |> deliverOn(self.queue)).start(next: { [weak self] messages in + if let strongSelf = self { + strongSelf.notificationMessagesPipe.putNext(messages) + } + }, error: { _ in + completed() + }, completed: { + completed() + }) + + if !events.displayAlerts.isEmpty { + self.displayAlertsPipe.putNext(events.displayAlerts) + } + + if !events.externallyUpdatedPeerId.isEmpty { + self.externallyUpdatedPeerIdsPipe.putNext(Array(events.externallyUpdatedPeerId)) + } + case let .pollCompletion(pollId, preMessageIds, preSubscribers): + if self.operations.count > 1 { + self.operations.removeFirst() + self.postponePollCompletionOperation(messageIds: preMessageIds, subscribers: preSubscribers) + self.startFirstOperation() + } else { + self.operationTimer?.invalidate() + let signal = self.network.request(Api.functions.help.test()) + |> deliverOn(self.queue) + let completed: () -> Void = { [weak self] in + if let strongSelf = self { + let topOperation = strongSelf.operations.removeFirst() + if case let .pollCompletion(topPollId, messageIds, subscribers) = topOperation.content { + assert(topPollId == pollId) + + if strongSelf.operations.isEmpty { + for (_, f) in subscribers { + f(messageIds) + } + } else { + strongSelf.postponePollCompletionOperation(messageIds: messageIds, subscribers: subscribers) + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + } + } + let _ = (signal |> deliverOn(self.queue)).start(error: { _ in + completed() + }, completed: { + completed() + }) + } + case let .replayAsynchronouslyBuiltFinalState(finalState, completion): + if !finalState.state.preCachedResources.isEmpty { + for (resource, data) in finalState.state.preCachedResources { + self.postbox.mediaBox.storeResourceData(resource.id, data: data) + } + } + + let accountPeerId = self.accountPeerId + let accountManager = self.accountManager + let postbox = self.postbox + let mediaBox = self.postbox.mediaBox + let auxiliaryMethods = self.auxiliaryMethods + let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in + let startTime = CFAbsoluteTimeGetCurrent() + let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime + if deltaTime > 1.0 { + Logger.shared.log("State", "replayFinalState took \(deltaTime)s") + } + return result + } + |> map({ ($0, finalState) }) + |> deliverOn(self.queue) + + let _ = signal.start(next: { [weak self] replayedState, finalState in + if let strongSelf = self { + if case .replayAsynchronouslyBuiltFinalState = strongSelf.operations.removeFirst().content { + if let replayedState = replayedState { + let events = AccountFinalStateEvents(state: replayedState) + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + completion() + } + }, error: { _ in + assertionFailure() + Logger.shared.log("AccountStateManager", "processUpdateGroups signal completed with error") + completion() + }) + } + } + + private func insertProcessEvents(_ events: AccountFinalStateEvents) { + if !events.isEmpty { + let operation = AccountStateManagerOperation(content: .processEvents(self.getNextId(), events)) + var inserted = false + for i in 0 ..< self.operations.count { + if self.operations[i].isRunning { + continue + } + if case .processEvents = self.operations[i].content { + continue + } + self.operations.insert(operation, at: i) + inserted = true + break + } + if !inserted { + self.operations.append(operation) + } + } + } + + private func postponePollCompletionOperation(messageIds: [MessageId], subscribers: [(Int32, ([MessageId]) -> Void)]) { + self.addOperation(.pollCompletion(self.getNextId(), messageIds, subscribers), position: .last) + + for i in 0 ..< self.operations.count { + if case .pollCompletion = self.operations[i].content { + if i != self.operations.count - 1 { + assertionFailure() + } + } + } + } + + private func addPollCompletion(_ f: @escaping ([MessageId]) -> Void) -> Int32 { + assert(self.queue.isCurrent()) + + let updatedId: Int32 = self.getNextId() + + for i in 0 ..< self.operations.count { + if case let .pollCompletion(pollId, messageIds, subscribers) = self.operations[i].content { + var subscribers = subscribers + subscribers.append((updatedId, f)) + let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, messageIds, subscribers)) + operation.isRunning = self.operations[i].isRunning + self.operations[i] = operation + return updatedId + } + } + + self.addOperation(.pollCompletion(self.getNextId(), [], [(updatedId, f)]), position: .last) + + return updatedId + } + + private func removePollCompletion(_ id: Int32) { + for i in 0 ..< self.operations.count { + if case let .pollCompletion(pollId, messages, subscribers) = self.operations[i].content { + for j in 0 ..< subscribers.count { + if subscribers[j].0 == id { + var subscribers = subscribers + subscribers.remove(at: j) + let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, messages, subscribers)) + operation.isRunning = self.operations[i].isRunning + self.operations[i] = operation + break + } + } + } + } + } + + public func pollStateUpdateCompletion() -> Signal<[MessageId], NoError> { + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + if let strongSelf = self { + strongSelf.queue.async { + let id = strongSelf.addPollCompletion({ messageIds in + subscriber.putNext(messageIds) + subscriber.putCompletion() + }) + + disposable.set(ActionDisposable { + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.removePollCompletion(id) + } + } + }) + } + } + return disposable + } + } + + public func updatedWebpage(_ webpageId: MediaId) -> Signal { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let context: UpdatedWebpageSubscriberContext + if let current = strongSelf.updatedWebpageContexts[webpageId] { + context = current + } else { + context = UpdatedWebpageSubscriberContext() + strongSelf.updatedWebpageContexts[webpageId] = context + } + + let index = context.subscribers.add({ media in + subscriber.putNext(media) + }) + + disposable.set(ActionDisposable { + if let strongSelf = self { + if let context = strongSelf.updatedWebpageContexts[webpageId] { + context.subscribers.remove(index) + if context.subscribers.isEmpty { + strongSelf.updatedWebpageContexts.removeValue(forKey: webpageId) + } + } + } + }) + } + } + return disposable + } + } + + private func notifyUpdatedWebpages(_ updatedWebpages: [MediaId: TelegramMediaWebpage]) { + for (id, context) in self.updatedWebpageContexts { + if let media = updatedWebpages[id] { + for subscriber in context.subscribers.copyItems() { + subscriber(media) + } + } + } + } + + func notifyAppliedIncomingReadMessages(_ ids: [MessageId]) { + self.appliedIncomingReadMessagesPipe.putNext(ids) + } + + public func getDelayNotificatonsUntil() -> Int32? { + return self.delayNotificatonsUntil.with { $0 } + } + + func modifyTermsOfServiceUpdate(_ f: @escaping (TermsOfServiceUpdate?) -> (TermsOfServiceUpdate?)) { + self.queue.async { + let current = self.termsOfServiceUpdateValue.with { $0 } + let updated = f(current) + if (current != updated) { + let _ = self.termsOfServiceUpdateValue.swap(updated) + self.termsOfServiceUpdatePromise.set(.single(updated)) + } + } + } + + public func updatedPeersNearby() -> Signal<[PeerNearby], NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let index = strongSelf.updatedPeersNearbyContext.subscribers.add({ peersNearby in + subscriber.putNext(peersNearby) + }) + + disposable.set(ActionDisposable { + if let strongSelf = self { + strongSelf.updatedPeersNearbyContext.subscribers.remove(index) + } + }) + } + } + return disposable + } + } + + private func notifyUpdatedPeersNearby(_ updatedPeersNearby: [PeerNearby]) { + for subscriber in self.updatedPeersNearbyContext.subscribers.copyItems() { + subscriber(updatedPeersNearby) + } + } +} + +public func messagesForNotification(transaction: Transaction, id: MessageId, alwaysReturnMessage: Bool) -> (messages: [Message], notify: Bool, sound: PeerMessageSound, displayContents: Bool) { + guard let message = transaction.getMessage(id) else { + Logger.shared.log("AccountStateManager", "notification message doesn't exist") + return ([], false, .bundledModern(id: 0), false) + } + + var notify = true + var sound: PeerMessageSound = .bundledModern(id: 0) + var muted = false + var displayContents = true + + for attribute in message.attributes { + if let attribute = attribute as? NotificationInfoMessageAttribute { + if attribute.flags.contains(.muted) { + muted = true + } + } + } + for media in message.media { + if let action = media as? TelegramMediaAction { + switch action.action { + case .groupMigratedToChannel, .channelMigratedFromGroup: + notify = false + default: + break + } + } + } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + + var notificationPeerId = id.peerId + let peer = transaction.getPeer(id.peerId) + if let peer = peer, let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + if message.personal, let author = message.author { + notificationPeerId = author.id + } + + if let notificationSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings { + var defaultSound: PeerMessageSound = .bundledModern(id: 0) + var defaultNotify: Bool = true + if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings { + if id.peerId.namespace == Namespaces.Peer.CloudUser { + defaultNotify = globalNotificationSettings.effective.privateChats.enabled + defaultSound = globalNotificationSettings.effective.privateChats.sound + displayContents = globalNotificationSettings.effective.privateChats.displayPreviews + } else if id.peerId.namespace == Namespaces.Peer.SecretChat { + defaultNotify = globalNotificationSettings.effective.privateChats.enabled + defaultSound = globalNotificationSettings.effective.privateChats.sound + displayContents = false + } else if id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = peer as? TelegramChannel, case .broadcast = peer.info { + defaultNotify = globalNotificationSettings.effective.channels.enabled + defaultSound = globalNotificationSettings.effective.channels.sound + displayContents = globalNotificationSettings.effective.channels.displayPreviews + } else { + defaultNotify = globalNotificationSettings.effective.groupChats.enabled + defaultSound = globalNotificationSettings.effective.groupChats.sound + displayContents = globalNotificationSettings.effective.groupChats.displayPreviews + } + } + switch notificationSettings.muteState { + case .default: + if !defaultNotify { + notify = false + } + case let .muted(until): + if until >= timestamp { + notify = false + } + case .unmuted: + break + } + if case .default = notificationSettings.messageSound { + sound = defaultSound + } else { + sound = notificationSettings.messageSound + } + } else { + Logger.shared.log("AccountStateManager", "notification settings for \(notificationPeerId) are undefined") + } + + if muted { + sound = .none + } + + if let channel = message.peers[message.id.peerId] as? TelegramChannel { + switch channel.participationStatus { + case .kicked, .left: + return ([], false, sound, false) + case .member: + break + } + } + + var foundReadState = false + var isUnread = true + if let readState = transaction.getCombinedPeerReadState(id.peerId) { + if readState.isIncomingMessageIndexRead(message.index) { + isUnread = false + } + foundReadState = true + } + + if !foundReadState { + Logger.shared.log("AccountStateManager", "read state for \(id.peerId) is undefined") + } + + var resultMessages: [Message] = [message] + + var messageGroup: [Message]? + if message.forwardInfo != nil && message.sourceReference == nil { + messageGroup = transaction.getMessageForwardedGroup(message.id) + } else if message.groupingKey != nil { + messageGroup = transaction.getMessageGroup(message.id) + } + if let messageGroup = messageGroup { + resultMessages.append(contentsOf: messageGroup.filter({ $0.id != message.id })) + } + + if notify { + return (resultMessages, isUnread, sound, displayContents) + } else { + return (alwaysReturnMessage ? resultMessages : [], false, sound, displayContents) + } +} diff --git a/submodules/TelegramCore/TelegramCore/AccountStateReset.swift b/submodules/TelegramCore/TelegramCore/AccountStateReset.swift new file mode 100644 index 0000000000..a44ba42543 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountStateReset.swift @@ -0,0 +1,299 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private struct LocalChatListEntryRange { + var entries: [ChatListNamespaceEntry] + var upperBound: ChatListIndex? + var lowerBound: ChatListIndex + var count: Int32 + var hash: UInt32 + + var apiHash: Int32 { + return Int32(bitPattern: self.hash & UInt32(0x7FFFFFFF)) + } +} + +private func combineHash(_ value: Int32, into hash: inout UInt32) { + let low = UInt32(bitPattern: value) + hash = (hash &* 20261) &+ low +} + +private func combineChatListNamespaceEntryHash(index: ChatListIndex, readState: PeerReadState?, topMessageAttributes: [MessageAttribute], tagSummary: MessageHistoryTagNamespaceSummary?, interfaceState: PeerChatInterfaceState?, into hash: inout UInt32) { + /* + dialog.pinned ? 1 : 0, + dialog.unread_mark ? 1 : 0, + dialog.peer.channel_id || dialog.peer.chat_id || dialog.peer.user_id, + dialog.top_message.id, + top_message.edit_date || top_message.date, + dialog.read_inbox_max_id, + dialog.read_outbox_max_id, + dialog.unread_count, + dialog.unread_mentions_count, + draft.draft.date || 0 + + */ + + combineHash(index.pinningIndex != nil ? 1 : 0, into: &hash) + if let readState = readState, readState.markedUnread { + combineHash(1, into: &hash) + } else { + combineHash(0, into: &hash) + } + combineHash(index.messageIndex.id.peerId.id, into: &hash) + combineHash(index.messageIndex.id.id, into: &hash) + var timestamp = index.messageIndex.timestamp + for attribute in topMessageAttributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = max(timestamp, attribute.date) + } + } + combineHash(timestamp, into: &hash) + if let readState = readState, case let .idBased(maxIncomingReadId, maxOutgoingReadId, _, count, _) = readState { + combineHash(maxIncomingReadId, into: &hash) + combineHash(maxOutgoingReadId, into: &hash) + combineHash(count, into: &hash) + } else { + combineHash(0, into: &hash) + combineHash(0, into: &hash) + combineHash(0, into: &hash) + } + + if let tagSummary = tagSummary { + combineHash(tagSummary.count, into: &hash) + } else { + combineHash(0, into: &hash) + } + + if let embeddedState = interfaceState?.chatListEmbeddedState { + combineHash(embeddedState.timestamp, into: &hash) + } else { + combineHash(0, into: &hash) + } +} + +private func localChatListEntryRanges(_ entries: [ChatListNamespaceEntry], limit: Int) -> [LocalChatListEntryRange] { + var result: [LocalChatListEntryRange] = [] + var currentRange: LocalChatListEntryRange? + for i in 0 ..< entries.count { + switch entries[i] { + case let .peer(index, readState, topMessageAttributes, tagSummary, interfaceState): + var updatedRange: LocalChatListEntryRange + if let current = currentRange { + updatedRange = current + } else { + updatedRange = LocalChatListEntryRange(entries: [], upperBound: result.last?.lowerBound, lowerBound: index, count: 0, hash: 0) + } + updatedRange.entries.append(entries[i]) + updatedRange.lowerBound = index + updatedRange.count += 1 + + combineChatListNamespaceEntryHash(index: index, readState: readState, topMessageAttributes: topMessageAttributes, tagSummary: tagSummary, interfaceState: interfaceState, into: &updatedRange.hash) + + if Int(updatedRange.count) >= limit { + result.append(updatedRange) + currentRange = nil + } else { + currentRange = updatedRange + } + case .hole: + if let currentRangeValue = currentRange { + result.append(currentRangeValue) + currentRange = nil + } + } + } + if let currentRangeValue = currentRange { + result.append(currentRangeValue) + currentRange = nil + } + return result +} + +private struct ResolvedChatListResetRange { + let head: Bool + let local: LocalChatListEntryRange + let remote: FetchedChatList +} + +/*func accountStateReset(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal { + let pinnedChats: Signal = network.request(Api.functions.messages.getPinnedDialogs(folderId: 0)) + |> retryRequest + let state: Signal = network.request(Api.functions.updates.getState()) + |> retryRequest + + return postbox.transaction { transaction -> [ChatListNamespaceEntry] in + return transaction.getChatListNamespaceEntries(groupId: .root, namespace: Namespaces.Message.Cloud, summaryTag: MessageTags.unseenPersonalMessage) + } + |> mapToSignal { localChatListEntries -> Signal in + let localRanges = localChatListEntryRanges(localChatListEntries, limit: 100) + var signal: Signal = .complete() + for i in 0 ..< localRanges.count { + let upperBound: MessageIndex + let head = i == 0 + let localRange = localRanges[i] + if let rangeUpperBound = localRange.upperBound { + upperBound = rangeUpperBound.messageIndex.predecessor() + } else { + upperBound = MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 0), timestamp: 0) + } + + let rangeSignal: Signal = fetchChatList(postbox: postbox, network: network, location: .general, upperBound: upperBound, hash: localRange.apiHash, limit: localRange.count) + |> map { remote -> ResolvedChatListResetRange? in + if let remote = remote { + return ResolvedChatListResetRange(head: head, local: localRange, remote: remote) + } else { + return nil + } + } + + signal = signal + |> then(rangeSignal) + } + let collectedResolvedRanges: Signal<[ResolvedChatListResetRange], NoError> = signal + |> map { next -> [ResolvedChatListResetRange] in + if let next = next { + return [next] + } else { + return [] + } + } + |> reduceLeft(value: [], f: { list, next in + var list = list + list.append(contentsOf: next) + return list + }) + + return combineLatest(collectedResolvedRanges, state) + |> mapToSignal { collectedRanges, state -> Signal in + return postbox.transaction { transaction -> Void in + for range in collectedRanges { + let previousPeerIds = transaction.resetChatList(keepPeerNamespaces: [Namespaces.Peer.SecretChat], upperBound: range.local.upperBound ?? ChatListIndex.absoluteUpperBound, lowerBound: range.local.lowerBound) + #if DEBUG + for peerId in previousPeerIds { + print("pre \(peerId) [\(transaction.getPeer(peerId)?.displayTitle ?? "nil")]") + } + print("pre hash \(range.local.hash)") + print("") + + var preRecalculatedHash: UInt32 = 0 + for entry in range.local.entries { + switch entry { + case let .peer(index, readState, topMessageAttributes, tagSummary, interfaceState): + print("val \(index.messageIndex.id.peerId) [\(transaction.getPeer(index.messageIndex.id.peerId)?.displayTitle ?? "nil")]") + combineChatListNamespaceEntryHash(index: index, readState: readState, topMessageAttributes: topMessageAttributes, tagSummary: nil, interfaceState: nil, into: &preRecalculatedHash) + default: + break + } + } + print("pre recalculated hash \(preRecalculatedHash)") + print("") + + var hash: UInt32 = 0 + range.remote.storeMessages.compactMap({ message -> MessageIndex? in + if case let .Id(id) = message.id { + if range.remote.topMessageIds[id.peerId] == id { + return message.index + } + } + return nil + }).sorted(by: { lhs, rhs in + return lhs > rhs + }).forEach({ index in + var topMessageAttributes: [MessageAttribute] = [] + for message in range.remote.storeMessages { + if case let .Id(id) = message.id, id == index.id { + topMessageAttributes = message.attributes + } + } + combineChatListNamespaceEntryHash(index: ChatListIndex(pinningIndex: nil, messageIndex: index), readState: range.remote.readStates[index.id.peerId]?[Namespaces.Message.Cloud], topMessageAttributes: topMessageAttributes, tagSummary: nil, interfaceState: nil, into: &hash) + print("upd \(index.id.peerId) [\(transaction.getPeer(index.id.peerId)?.displayTitle ?? "nil")]") + }) + print("upd hash \(hash)") + #endif + + updatePeers(transaction: transaction, peers: range.remote.peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: range.remote.peerPresences) + + transaction.updateCurrentPeerNotificationSettings(range.remote.notificationSettings) + + var allPeersWithMessages = Set() + for message in range.remote.storeMessages { + allPeersWithMessages.insert(message.id.peerId) + } + + for (_, messageId) in range.remote.topMessageIds { + if messageId.id > 1 { + var skipHole = false + if let localTopId = transaction.getTopPeerMessageIndex(peerId: messageId.peerId, namespace: messageId.namespace)?.id { + if localTopId >= messageId { + skipHole = true + } + } + if !skipHole { + //transaction.addHole(MessageId(peerId: messageId.peerId, namespace: messageId.namespace, id: messageId.id - 1)) + } + } + } + + let _ = transaction.addMessages(range.remote.storeMessages, location: .UpperHistoryBlock) + + transaction.resetIncomingReadStates(range.remote.readStates) + + for (peerId, chatState) in range.remote.chatStates { + if let chatState = chatState as? ChannelState { + if let current = transaction.getPeerChatState(peerId) as? ChannelState { + transaction.setPeerChatState(peerId, state: current.withUpdatedPts(chatState.pts)) + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } + + for (peerId, summary) in range.remote.mentionTagSummaries { + transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId) + } + + let namespacesWithHoles: [PeerId.Namespace: [MessageId.Namespace]] = [ + Namespaces.Peer.CloudUser: [Namespaces.Message.Cloud], + Namespaces.Peer.CloudGroup: [Namespaces.Message.Cloud], + Namespaces.Peer.CloudChannel: [Namespaces.Message.Cloud] + ] + for peerId in previousPeerIds { + if !allPeersWithMessages.contains(peerId), let namespaces = namespacesWithHoles[peerId.namespace] { + for namespace in namespaces { + //transaction.addHole(MessageId(peerId: peerId, namespace: namespace, id: Int32.max - 1)) + } + } + } + + if range.head { + transaction.setPinnedItemIds(groupId: nil, itemIds: range.remote.pinnedItemIds ?? []) + } + } + + if let currentState = transaction.getState() as? AuthorizedAccountState, let embeddedState = currentState.state { + switch state { + case let .state(pts, _, _, seq, _): + transaction.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: embeddedState.qts, date: embeddedState.date, seq: seq))) + } + } + } + } + } +}*/ diff --git a/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift b/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift new file mode 100644 index 0000000000..b1153c0a04 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift @@ -0,0 +1,1218 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum CallListViewType { + case all + case missed +} + +public enum CallListViewEntry { + case message(Message, [Message]) + case hole(MessageIndex) +} + +public final class CallListView { + public let entries: [CallListViewEntry] + public let earlier: MessageIndex? + public let later: MessageIndex? + + init(entries: [CallListViewEntry], earlier: MessageIndex?, later: MessageIndex?) { + self.entries = entries + self.earlier = earlier + self.later = later + } +} + +private func pendingWebpages(entries: [MessageHistoryEntry]) -> (Set, [MessageId: (MediaId, String)]) { + var messageIds = Set() + var localWebpages: [MessageId: (MediaId, String)] = [:] + for entry in entries { + for media in entry.message.media { + if let media = media as? TelegramMediaWebpage { + if case let .Pending(_, url) = media.content { + messageIds.insert(entry.message.id) + if let url = url, media.webpageId.namespace == Namespaces.Media.LocalWebpage { + localWebpages[entry.message.id] = (media.webpageId, url) + } + } + break + } + } + } + return (messageIds, localWebpages) +} + +private func pollMessages(entries: [MessageHistoryEntry]) -> (Set, [MessageId: Message]) { + var messageIds = Set() + var messages: [MessageId: Message] = [:] + for entry in entries { + for media in entry.message.media { + if let poll = media as? TelegramMediaPoll, poll.pollId.namespace == Namespaces.Media.CloudPoll, entry.message.id.namespace == Namespaces.Message.Cloud, !poll.isClosed { + messageIds.insert(entry.message.id) + messages[entry.message.id] = entry.message + break + } + } + } + return (messageIds, messages) +} + +private func fetchWebpage(account: Account, messageId: MessageId) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + let messages: Signal + switch inputPeer { + case let .inputPeerChannel(channelId, accessHash): + messages = account.network.request(Api.functions.channels.getMessages(channel: Api.InputChannel.inputChannel(channelId: channelId, accessHash: accessHash), id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + default: + messages = account.network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + } + return messages + |> retryRequest + |> mapToSignal { result in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + + return account.postbox.transaction { transaction -> Void in + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + var webpage: TelegramMediaWebpage? + for media in storeMessage.media { + if let media = media as? TelegramMediaWebpage { + webpage = media + } + } + + if let webpage = webpage { + updateMessageMedia(transaction: transaction, id: webpage.webpageId, media: webpage) + } else { + if let previousMessage = transaction.getMessage(messageId) { + for media in previousMessage.media { + if let media = media as? TelegramMediaWebpage { + updateMessageMedia(transaction: transaction, id: media.webpageId, media: nil) + + break + } + } + } + } + break + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) + } + } + } else { + return .complete() + } + } +} + +private func fetchPoll(account: Account, messageId: MessageId) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> mapToSignal { peer -> Signal in + guard let inputPeer = apiInputPeer(peer) else { + return .complete() + } + return account.network.request(Api.functions.messages.getPollResults(peer: inputPeer, msgId: messageId.id)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + } + return .complete() + } + } +} + +private func wrappedHistoryViewAdditionalData(chatLocation: ChatLocation, additionalData: [AdditionalMessageHistoryViewData]) -> [AdditionalMessageHistoryViewData] { + var result = additionalData + switch chatLocation { + case let .peer(peerId): + if peerId.namespace == Namespaces.Peer.CloudChannel { + if result.index(where: { if case .peerChatState = $0 { return true } else { return false } }) == nil { + result.append(.peerChatState(peerId)) + } + } + /*case let .group(groupId): + if result.index(where: { if case .peerGroupState = $0 { return true } else { return false } }) == nil { + result.append(.peerGroupState(groupId)) + }*/ + } + return result +} + +private final class PeerCachedDataContext { + var viewIds = Set() + var timestamp: Double? + var referenceData: CachedPeerData? + let disposable = MetaDisposable() + + deinit { + self.disposable.dispose() + } +} + +private final class CachedChannelParticipantsContext { + var subscribers = Bag() + var timestamp: Double? + let disposable = MetaDisposable() + + deinit { + self.disposable.dispose() + } +} + +private final class ChannelPollingContext { + var subscribers = Bag() + let disposable = MetaDisposable() + + deinit { + self.disposable.dispose() + } +} + +private final class FeaturedStickerPacksContext { + var subscribers = Bag() + let disposable = MetaDisposable() + var timestamp: Double? + + deinit { + self.disposable.dispose() + } +} + +public final class AccountViewTracker { + weak var account: Account? + private let queue = Queue() + private var nextViewId: Int32 = 0 + + private var viewPendingWebpageMessageIds: [Int32: Set] = [:] + private var viewPollMessageIds: [Int32: Set] = [:] + private var pendingWebpageMessageIds: [MessageId: Int] = [:] + private var pollMessageIds: [MessageId: Int] = [:] + private var webpageDisposables: [MessageId: Disposable] = [:] + private var pollDisposables: [MessageId: Disposable] = [:] + + private var viewVisibleCallListHoleIds: [Int32: Set] = [:] + private var visibleCallListHoleIds: [MessageIndex: Int] = [:] + private var visibleCallListHoleDisposables: [MessageIndex: Disposable] = [:] + + private var updatedViewCountMessageIdsAndTimestamps: [MessageId: Int32] = [:] + private var nextUpdatedViewCountDisposableId: Int32 = 0 + private var updatedViewCountDisposables = DisposableDict() + + private var updatedUnsupportedMediaMessageIdsAndTimestamps: [MessageId: Int32] = [:] + private var nextUpdatedUnsupportedMediaDisposableId: Int32 = 0 + private var updatedUnsupportedMediaDisposables = DisposableDict() + + private var updatedSeenPersonalMessageIds = Set() + + private var cachedDataContexts: [PeerId: PeerCachedDataContext] = [:] + private var cachedChannelParticipantsContexts: [PeerId: CachedChannelParticipantsContext] = [:] + + private var channelPollingContexts: [PeerId: ChannelPollingContext] = [:] + private var featuredStickerPacksContext: FeaturedStickerPacksContext? + + let chatHistoryPreloadManager: ChatHistoryPreloadManager + + private let historyViewStateValidationContexts: HistoryViewStateValidationContexts + + public var orderedPreloadMedia: Signal<[ChatHistoryPreloadMediaItem], NoError> { + return self.chatHistoryPreloadManager.orderedMedia + } + + private let externallyUpdatedPeerIdDisposable = MetaDisposable() + + init(account: Account) { + self.account = account + + self.historyViewStateValidationContexts = HistoryViewStateValidationContexts(queue: self.queue, postbox: account.postbox, network: account.network, accountPeerId: account.peerId) + + self.chatHistoryPreloadManager = ChatHistoryPreloadManager(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, networkState: account.networkState) + + self.externallyUpdatedPeerIdDisposable.set((account.stateManager.externallyUpdatedPeerIds + |> deliverOn(self.queue)).start(next: { [weak self] peerIds in + guard let strongSelf = self else { + return + } + for (peerId, _) in strongSelf.cachedDataContexts { + if peerIds.contains(peerId) { + strongSelf.forceUpdateCachedPeerData(peerId: peerId) + } + } + })) + } + + deinit { + self.updatedViewCountDisposables.dispose() + self.externallyUpdatedPeerIdDisposable.dispose() + } + + func reset() { + self.queue.async { + self.cachedDataContexts.removeAll() + } + } + + private func updatePendingWebpages(viewId: Int32, messageIds: Set, localWebpages: [MessageId: (MediaId, String)]) { + self.queue.async { + var addedMessageIds: [MessageId] = [] + var removedMessageIds: [MessageId] = [] + + let viewMessageIds: Set = self.viewPendingWebpageMessageIds[viewId] ?? Set() + + let viewAddedMessageIds = messageIds.subtracting(viewMessageIds) + let viewRemovedMessageIds = viewMessageIds.subtracting(messageIds) + for messageId in viewAddedMessageIds { + if let count = self.pendingWebpageMessageIds[messageId] { + self.pendingWebpageMessageIds[messageId] = count + 1 + } else { + self.pendingWebpageMessageIds[messageId] = 1 + addedMessageIds.append(messageId) + } + } + for messageId in viewRemovedMessageIds { + if let count = self.pendingWebpageMessageIds[messageId] { + if count == 1 { + self.pendingWebpageMessageIds.removeValue(forKey: messageId) + removedMessageIds.append(messageId) + } else { + self.pendingWebpageMessageIds[messageId] = count - 1 + } + } else { + assertionFailure() + } + } + + if messageIds.isEmpty { + self.viewPendingWebpageMessageIds.removeValue(forKey: viewId) + } else { + self.viewPendingWebpageMessageIds[viewId] = messageIds + } + + for messageId in removedMessageIds { + if let disposable = self.webpageDisposables.removeValue(forKey: messageId) { + disposable.dispose() + } + } + + if let account = self.account { + for messageId in addedMessageIds { + if self.webpageDisposables[messageId] == nil { + if let (_, url) = localWebpages[messageId] { + self.webpageDisposables[messageId] = (webpagePreview(account: account, url: url) |> mapToSignal { webpage -> Signal in + return account.postbox.transaction { transaction -> Void in + if let webpage = webpage { + transaction.updateMessage(messageId, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var media = currentMessage.media + for i in 0 ..< media.count { + if let _ = media[i] as? TelegramMediaWebpage { + media[i] = webpage + break + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media)) + }) + } + } + }).start(completed: { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.webpageDisposables.removeValue(forKey: messageId) + } + } + }) + } else if messageId.namespace == Namespaces.Message.Cloud { + self.webpageDisposables[messageId] = fetchWebpage(account: account, messageId: messageId).start(completed: { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.webpageDisposables.removeValue(forKey: messageId) + } + } + }) + } + } else { + assertionFailure() + } + } + } + } + } + + private func updatePolls(viewId: Int32, messageIds: Set, messages: [MessageId: Message]) { + self.queue.async { + var addedMessageIds: [MessageId] = [] + var removedMessageIds: [MessageId] = [] + + let viewMessageIds: Set = self.viewPollMessageIds[viewId] ?? Set() + + let viewAddedMessageIds = messageIds.subtracting(viewMessageIds) + let viewRemovedMessageIds = viewMessageIds.subtracting(messageIds) + for messageId in viewAddedMessageIds { + if let count = self.pollMessageIds[messageId] { + self.pollMessageIds[messageId] = count + 1 + } else { + self.pollMessageIds[messageId] = 1 + addedMessageIds.append(messageId) + } + } + for messageId in viewRemovedMessageIds { + if let count = self.pollMessageIds[messageId] { + if count == 1 { + self.pollMessageIds.removeValue(forKey: messageId) + removedMessageIds.append(messageId) + } else { + self.pollMessageIds[messageId] = count - 1 + } + } else { + assertionFailure() + } + } + + if messageIds.isEmpty { + self.viewPollMessageIds.removeValue(forKey: viewId) + } else { + self.viewPollMessageIds[viewId] = messageIds + } + + for messageId in removedMessageIds { + if let disposable = self.pollDisposables.removeValue(forKey: messageId) { + disposable.dispose() + } + } + + if let account = self.account { + for messageId in addedMessageIds { + if self.pollDisposables[messageId] == nil { + var signal: Signal = fetchPoll(account: account, messageId: messageId) + |> ignoreValues + signal = (signal |> then( + .complete() + |> delay(30.0, queue: Queue.concurrentDefaultQueue()) + )) |> restart + self.pollDisposables[messageId] = signal.start() + } else { + assertionFailure() + } + } + } + } + } + + private func updateVisibleCallListHoles(viewId: Int32, holeIds: Set) { + self.queue.async { + var addedHoleIds: [MessageIndex] = [] + var removedHoleIds: [MessageIndex] = [] + + let viewHoleIds: Set = self.viewVisibleCallListHoleIds[viewId] ?? Set() + + let viewAddedHoleIds = holeIds.subtracting(viewHoleIds) + let viewRemovedHoleIds = viewHoleIds.subtracting(holeIds) + for holeId in viewAddedHoleIds { + if let count = self.visibleCallListHoleIds[holeId] { + self.visibleCallListHoleIds[holeId] = count + 1 + } else { + self.visibleCallListHoleIds[holeId] = 1 + addedHoleIds.append(holeId) + } + } + for holeId in viewRemovedHoleIds { + if let count = self.visibleCallListHoleIds[holeId] { + if count == 1 { + self.visibleCallListHoleIds.removeValue(forKey: holeId) + removedHoleIds.append(holeId) + } else { + self.visibleCallListHoleIds[holeId] = count - 1 + } + } else { + assertionFailure() + } + } + + if holeIds.isEmpty { + self.viewVisibleCallListHoleIds.removeValue(forKey: viewId) + } else { + self.viewVisibleCallListHoleIds[viewId] = holeIds + } + + for holeId in removedHoleIds { + if let disposable = self.visibleCallListHoleDisposables.removeValue(forKey: holeId) { + disposable.dispose() + } + } + + if let account = self.account { + for holeId in addedHoleIds { + if self.visibleCallListHoleDisposables[holeId] == nil { + self.visibleCallListHoleDisposables[holeId] = fetchCallListHole(network: account.network, postbox: account.postbox, accountPeerId: account.peerId, holeIndex: holeId).start(completed: { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.visibleCallListHoleDisposables.removeValue(forKey: holeId) + } + } + }) + } else { + assertionFailure() + } + } + } + } + } + + public func updateViewCountForMessageIds(messageIds: Set) { + self.queue.async { + var addedMessageIds: [MessageId] = [] + let timestamp = Int32(CFAbsoluteTimeGetCurrent()) + for messageId in messageIds { + let messageTimestamp = self.updatedViewCountMessageIdsAndTimestamps[messageId] + if messageTimestamp == nil || messageTimestamp! < timestamp - 5 * 60 { + self.updatedViewCountMessageIdsAndTimestamps[messageId] = timestamp + addedMessageIds.append(messageId) + } + } + if !addedMessageIds.isEmpty { + for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(addedMessageIds)) { + let disposableId = self.nextUpdatedViewCountDisposableId + self.nextUpdatedViewCountDisposableId += 1 + + if let account = self.account { + let signal = (account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.getMessagesViews(peer: inputPeer, id: messageIds.map { $0.id }, increment: .boolTrue)) + |> map(Optional.init) + |> `catch` { _ -> Signal<[Int32]?, NoError> in + return .single(nil) + } + |> mapToSignal { viewCounts -> Signal in + if let viewCounts = viewCounts { + return account.postbox.transaction { transaction -> Void in + for i in 0 ..< messageIds.count { + if i < viewCounts.count { + transaction.updateMessage(messageIds[i], update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ViewCountMessageAttribute { + if attribute.count >= Int(viewCounts[i]) { + return .skip + } + attributes[j] = ViewCountMessageAttribute(count: max(attribute.count, Int(viewCounts[i]))) + break loop + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + } + } else { + return .complete() + } + } + } else { + return .complete() + } + } |> switchToLatest) + |> afterDisposed { [weak self] in + self?.queue.async { + self?.updatedViewCountDisposables.set(nil, forKey: disposableId) + } + } + self.updatedViewCountDisposables.set(signal.start(), forKey: disposableId) + } + } + } + } + } + + public func updateUnsupportedMediaForMessageIds(messageIds: Set) { + self.queue.async { + var addedMessageIds: [MessageId] = [] + let timestamp = Int32(CFAbsoluteTimeGetCurrent()) + for messageId in messageIds { + let messageTimestamp = self.updatedUnsupportedMediaMessageIdsAndTimestamps[messageId] + if messageTimestamp == nil || messageTimestamp! < timestamp - 10 * 60 * 60 { + self.updatedUnsupportedMediaMessageIdsAndTimestamps[messageId] = timestamp + addedMessageIds.append(messageId) + } + } + if !addedMessageIds.isEmpty { + for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(addedMessageIds)) { + let disposableId = self.nextUpdatedUnsupportedMediaDisposableId + self.nextUpdatedUnsupportedMediaDisposableId += 1 + + if let account = self.account { + let signal = account.postbox.transaction { transaction -> Peer? in + if let peer = transaction.getPeer(peerId) { + return peer + } else { + return nil + } + } + |> mapToSignal { peer -> Signal in + guard let peer = peer else { + return .complete() + } + var fetchSignal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + fetchSignal = account.network.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + fetchSignal = account.network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } + } + guard let signal = fetchSignal else { + return .complete() + } + + return signal + |> map { result -> ([Api.Message], [Api.Chat], [Api.User]) in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, messages, chats, users): + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } + |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + } + |> mapToSignal { messages, chats, users -> Signal in + return account.postbox.transaction { transaction -> Void in + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) + + for message in messages { + guard let storeMessage = StoreMessage(apiMessage: message) else { + continue + } + guard case let .Id(id) = storeMessage.id else { + continue + } + transaction.updateMessage(id, update: { _ in + return .update(storeMessage) + }) + } + } + } + } + |> afterDisposed { [weak self] in + self?.queue.async { + self?.updatedUnsupportedMediaDisposables.set(nil, forKey: disposableId) + } + } + self.updatedUnsupportedMediaDisposables.set(signal.start(), forKey: disposableId) + } + } + } + } + } + + public func updateMarkAllMentionsSeen(peerId: PeerId) { + self.queue.async { + guard let account = self.account else { + return + } + let _ = (account.postbox.transaction { transaction -> Set in + let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id })) + if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 { + var maxId: Int32 = summary.range.maxId + if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) { + maxId = index.id.id + } + + transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: maxId) + addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId) + } + + return ids + } + |> deliverOn(self.queue)).start(next: { [weak self] messageIds in + //self?.updateMarkMentionsSeenForMessageIds(messageIds: messageIds) + }) + } + } + + public func updateMarkMentionsSeenForMessageIds(messageIds: Set) { + self.queue.async { + var addedMessageIds: [MessageId] = [] + for messageId in messageIds { + if !self.updatedSeenPersonalMessageIds.contains(messageId) { + self.updatedSeenPersonalMessageIds.insert(messageId) + addedMessageIds.append(messageId) + } + } + if !addedMessageIds.isEmpty { + if let account = self.account { + let _ = (account.postbox.transaction { transaction -> Void in + for id in addedMessageIds { + if let message = transaction.getMessage(id) { + var consume = false + inner: for attribute in message.attributes { + if let attribute = attribute as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed, !attribute.pending { + consume = true + break inner + } + } + if consume { + transaction.updateMessage(id, update: { currentMessage in + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ConsumablePersonalMentionMessageAttribute { + attributes[j] = ConsumablePersonalMentionMessageAttribute(consumed: attribute.consumed, pending: true) + break loop + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: ConsumePersonalMessageAction()) + } + } + } + }).start() + } + } + } + } + + public func forceUpdateCachedPeerData(peerId: PeerId) { + self.queue.async { + let context: PeerCachedDataContext + if let existingContext = self.cachedDataContexts[peerId] { + context = existingContext + } else { + context = PeerCachedDataContext() + self.cachedDataContexts[peerId] = context + } + context.timestamp = CFAbsoluteTimeGetCurrent() + if let account = self.account { + context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox), fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start()) + } + } + } + + private func updateCachedPeerData(peerId: PeerId, viewId: Int32, referenceData: CachedPeerData?) { + self.queue.async { + let context: PeerCachedDataContext + var dataUpdated = false + if let existingContext = self.cachedDataContexts[peerId] { + context = existingContext + context.referenceData = referenceData + if context.timestamp == nil || abs(CFAbsoluteTimeGetCurrent() - context.timestamp!) > 60.0 * 5 { + context.timestamp = CFAbsoluteTimeGetCurrent() + dataUpdated = true + } + } else { + context = PeerCachedDataContext() + context.referenceData = referenceData + self.cachedDataContexts[peerId] = context + if context.referenceData == nil || context.timestamp == nil || abs(CFAbsoluteTimeGetCurrent() - context.timestamp!) > 60.0 * 5 { + context.timestamp = CFAbsoluteTimeGetCurrent() + dataUpdated = true + } + } + context.viewIds.insert(viewId) + + if dataUpdated { + if let account = self.account { + context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox), fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start()) + } + } + } + } + + private func removePeerView(peerId: PeerId, id: Int32) { + self.queue.async { + if let context = self.cachedDataContexts[peerId] { + context.viewIds.remove(id) + if context.viewIds.isEmpty { + context.disposable.set(nil) + context.referenceData = nil + } + } + } + } + + func polledChannel(peerId: PeerId) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.queue.async { + let context: ChannelPollingContext + if let current = self.channelPollingContexts[peerId] { + context = current + } else { + context = ChannelPollingContext() + self.channelPollingContexts[peerId] = context + } + + if context.subscribers.isEmpty { + if let account = self.account { + context.disposable.set(keepPollingChannel(postbox: account.postbox, network: account.network, peerId: peerId, stateManager: account.stateManager).start()) + } + } + + let index = context.subscribers.add(Void()) + + disposable.set(ActionDisposable { + self.queue.async { + if let context = self.channelPollingContexts[peerId] { + context.subscribers.remove(index) + if context.subscribers.isEmpty { + context.disposable.set(nil) + } + } + } + }) + } + + return disposable + } + } + + func wrappedMessageHistorySignal(chatLocation: ChatLocation, signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + let history = withState(signal, { [weak self] () -> Int32 in + if let strongSelf = self { + return OSAtomicIncrement32(&strongSelf.nextViewId) + } else { + return -1 + } + }, next: { [weak self] next, viewId in + if let strongSelf = self { + strongSelf.queue.async { + let (messageIds, localWebpages) = pendingWebpages(entries: next.0.entries) + strongSelf.updatePendingWebpages(viewId: viewId, messageIds: messageIds, localWebpages: localWebpages) + let (pollMessageIds, pollMessageDict) = pollMessages(entries: next.0.entries) + strongSelf.updatePolls(viewId: viewId, messageIds: pollMessageIds, messages: pollMessageDict) + if case let .peer(peerId) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel { + strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0) + }/* else if case .group = chatLocation { + strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0) + }*/ + } + } + }, disposed: { [weak self] viewId in + if let strongSelf = self { + strongSelf.queue.async { + strongSelf.updatePendingWebpages(viewId: viewId, messageIds: [], localWebpages: [:]) + strongSelf.updatePolls(viewId: viewId, messageIds: [], messages: [:]) + switch chatLocation { + case let .peer(peerId): + if peerId.namespace == Namespaces.Peer.CloudChannel { + strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil) + } + /*case .group: + strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil)*/ + } + } + } + }) + + if case let .peer(peerId) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel { + return Signal { subscriber in + let disposable = history.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + let polled = self.polledChannel(peerId: peerId).start() + return ActionDisposable { + disposable.dispose() + polled.dispose() + } + } + } else { + return history + } + } + + public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + if let account = self.account { + let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData)) + return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal) + } else { + return .never() + } + } + + public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocation, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + if let account = self.account { + let signal = account.postbox.aroundIdMessageHistoryViewForLocation(chatLocation, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData)) + return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal) + } else { + return .never() + } + } + + public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + if let account = self.account { + let inputAnchor: HistoryViewInputAnchor + switch index { + case .upperBound: + inputAnchor = .upperBound + case .lowerBound: + inputAnchor = .lowerBound + case let .message(index): + inputAnchor = .index(index) + } + let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData)) + return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal) + } else { + return .never() + } + } + + func wrappedPeerViewSignal(peerId: PeerId, signal: Signal, updateData: Bool) -> Signal { + if updateData { + self.queue.async { + if let existingContext = self.cachedDataContexts[peerId] { + existingContext.timestamp = nil + } + } + } + return withState(signal, { [weak self] () -> Int32 in + if let strongSelf = self { + return OSAtomicIncrement32(&strongSelf.nextViewId) + } else { + return -1 + } + }, next: { [weak self] next, viewId in + if let strongSelf = self { + strongSelf.updateCachedPeerData(peerId: peerId, viewId: viewId, referenceData: next.cachedData) + } + }, disposed: { [weak self] viewId in + if let strongSelf = self { + strongSelf.removePeerView(peerId: peerId, id: viewId) + } + }) + } + + public func peerView(_ peerId: PeerId, updateData: Bool = false) -> Signal { + if let account = self.account { + return wrappedPeerViewSignal(peerId: peerId, signal: account.postbox.peerView(id: peerId), updateData: updateData) + } else { + return .never() + } + } + + public func featuredStickerPacks() -> Signal<[FeaturedStickerPackItem], NoError> { + return Signal { subscriber in + if let account = self.account { + let view = account.postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)]).start(next: { next in + if let view = next.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)] as? OrderedItemListView { + subscriber.putNext(view.items.map { $0.contents as! FeaturedStickerPackItem }) + } else { + subscriber.putNext([]) + } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + let disposable = MetaDisposable() + self.queue.async { + let context: FeaturedStickerPacksContext + if let current = self.featuredStickerPacksContext { + context = current + } else { + context = FeaturedStickerPacksContext() + self.featuredStickerPacksContext = context + } + + let timestamp = CFAbsoluteTimeGetCurrent() + if context.timestamp == nil || abs(context.timestamp! - timestamp) > 60.0 * 60.0 { + context.timestamp = timestamp + context.disposable.set(updatedFeaturedStickerPacks(network: account.network, postbox: account.postbox).start()) + } + + let index = context.subscribers.add(Void()) + + disposable.set(ActionDisposable { + self.queue.async { + if let context = self.featuredStickerPacksContext { + context.subscribers.remove(index) + } + } + }) + } + return ActionDisposable { + view.dispose() + disposable.dispose() + } + } else { + subscriber.putNext([]) + subscriber.putCompletion() + return EmptyDisposable + } + } + } + + public func callListView(type: CallListViewType, index: MessageIndex, count: Int) -> Signal { + if let account = self.account { + let granularity: Int32 = 60 * 60 * 24 + let timezoneOffset: Int32 = { + let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + var now: time_t = time_t(nowTimestamp) + var timeinfoNow: tm = tm() + localtime_r(&now, &timeinfoNow) + return Int32(timeinfoNow.tm_gmtoff) + }() + + let groupingPredicate: (Message, Message) -> Bool = { lhs, rhs in + if lhs.id.peerId != rhs.id.peerId { + return false + } + let lhsTimestamp = ((lhs.timestamp + timezoneOffset) / (granularity)) * (granularity) + let rhsTimestamp = ((rhs.timestamp + timezoneOffset) / (granularity)) * (granularity) + if lhsTimestamp != rhsTimestamp { + return false + } + var lhsMissed = false + var lhsOther = false + inner: for media in lhs.media { + if let action = media as? TelegramMediaAction { + if case let .phoneCall(_, discardReason, _) = action.action { + if lhs.flags.contains(.Incoming), let discardReason = discardReason, case .missed = discardReason { + lhsMissed = true + } else { + lhsOther = true + } + break inner + } + } + } + var rhsMissed = false + var rhsOther = false + inner: for media in rhs.media { + if let action = media as? TelegramMediaAction { + if case let .phoneCall(_, discardReason, _) = action.action { + if rhs.flags.contains(.Incoming), let discardReason = discardReason, case .missed = discardReason { + rhsMissed = true + } else { + rhsOther = true + } + break inner + } + } + } + if lhsMissed != rhsMissed || lhsOther != rhsOther { + return false + } + return true + } + + let key = PostboxViewKey.globalMessageTags(globalTag: type == .all ? GlobalMessageTags.Calls : GlobalMessageTags.MissedCalls, position: index, count: 200, groupingPredicate: groupingPredicate) + let signal = account.postbox.combinedView(keys: [key]) |> map { view -> GlobalMessageTagsView in + let messageView = view.views[key] as! GlobalMessageTagsView + return messageView + } + + let managed = withState(signal, { [weak self] () -> Int32 in + if let strongSelf = self { + return OSAtomicIncrement32(&strongSelf.nextViewId) + } else { + return -1 + } + }, next: { [weak self] next, viewId in + if let strongSelf = self { + var holes = Set() + for entry in next.entries { + if case let .hole(index) = entry { + holes.insert(index) + } + } + strongSelf.updateVisibleCallListHoles(viewId: viewId, holeIds: holes) + } + }, disposed: { [weak self] viewId in + if let strongSelf = self { + strongSelf.updateVisibleCallListHoles(viewId: viewId, holeIds: Set()) + } + }) + + return managed + |> map { view -> CallListView in + var entries: [CallListViewEntry] = [] + if !view.entries.isEmpty { + var currentMessages: [Message] = [] + for entry in view.entries { + switch entry { + case let .hole(index): + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + //entries.append(.hole(index)) + case let .message(message): + if currentMessages.isEmpty || groupingPredicate(message, currentMessages[currentMessages.count - 1]) { + currentMessages.append(message) + } else { + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + currentMessages.append(message) + } + } + } + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + } + return CallListView(entries: entries, earlier: view.earlier, later: view.later) + } + } else { + return .never() + } + } + + public func unseenPersonalMessagesCount(peerId: PeerId) -> Signal { + if let account = self.account { + let pendingKey: PostboxViewKey = .pendingMessageActionsSummary(type: .consumeUnseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud) + let summaryKey: PostboxViewKey = .historyTagSummaryView(tag: .unseenPersonalMessage, peerId: peerId, namespace: Namespaces.Message.Cloud) + return account.postbox.combinedView(keys: [pendingKey, summaryKey]) + |> map { views -> Int32 in + var count: Int32 = 0 + if let view = views.views[pendingKey] as? PendingMessageActionsSummaryView { + count -= view.count + } + if let view = views.views[summaryKey] as? MessageHistoryTagSummaryView { + if let unseenCount = view.count { + count += unseenCount + } + } + return max(0, count) + } |> distinctUntilChanged + } else { + return .never() + } + } + + private func wrappedChatListView(signal: Signal<(ChatListView, ViewUpdateType), NoError>) -> Signal<(ChatListView, ViewUpdateType), NoError> { + return withState(signal, { [weak self] () -> Int32 in + if let strongSelf = self { + return OSAtomicIncrement32(&strongSelf.nextViewId) + } else { + return -1 + } + }, next: { [weak self] next, viewId in + if let strongSelf = self { + strongSelf.queue.async { + + } + } + }, disposed: { [weak self] viewId in + if let strongSelf = self { + strongSelf.queue.async { + + } + } + }) + } + + public func tailChatListView(groupId: PeerGroupId, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> { + if let account = self.account { + return self.wrappedChatListView(signal: account.postbox.tailChatListView(groupId: groupId, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)))) + } else { + return .never() + } + } + + public func aroundChatListView(groupId: PeerGroupId, index: ChatListIndex, count: Int) -> Signal<(ChatListView, ViewUpdateType), NoError> { + if let account = self.account { + return self.wrappedChatListView(signal: account.postbox.aroundChatListView(groupId: groupId, index: index, count: count, summaryComponents: ChatListEntrySummaryComponents(tagSummary: ChatListEntryMessageTagSummaryComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)))) + } else { + return .never() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift b/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift new file mode 100644 index 0000000000..7c124feebe --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ActiveSessionsContext.swift @@ -0,0 +1,115 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct ActiveSessionsContextState: Equatable { + public var isLoadingMore: Bool + public var sessions: [RecentAccountSession] +} + +public final class ActiveSessionsContext { + private let account: Account + private var _state: ActiveSessionsContextState { + didSet { + if self._state != oldValue { + self._statePromise.set(.single(self._state)) + } + } + } + private let _statePromise = Promise() + public var state: Signal { + return self._statePromise.get() + } + + private let disposable = MetaDisposable() + + public init(account: Account) { + assert(Queue.mainQueue().isCurrent()) + + self.account = account + self._state = ActiveSessionsContextState(isLoadingMore: false, sessions: []) + self._statePromise.set(.single(self._state)) + + self.loadMore() + } + + deinit { + assert(Queue.mainQueue().isCurrent()) + self.disposable.dispose() + } + + public func loadMore() { + assert(Queue.mainQueue().isCurrent()) + + if self._state.isLoadingMore { + return + } + self._state = ActiveSessionsContextState(isLoadingMore: true, sessions: self._state.sessions) + self.disposable.set((requestRecentAccountSessions(account: account) + |> map { result -> (sessions: [RecentAccountSession], canLoadMore: Bool) in + return (result, false) + } + |> deliverOnMainQueue).start(next: { [weak self] (sessions, canLoadMore) in + guard let strongSelf = self else { + return + } + + strongSelf._state = ActiveSessionsContextState(isLoadingMore: false, sessions: sessions) + })) + } + + public func remove(hash: Int64) -> Signal { + assert(Queue.mainQueue().isCurrent()) + + return terminateAccountSession(account: self.account, hash: hash) + |> deliverOnMainQueue + |> mapToSignal { [weak self] _ -> Signal in + guard let strongSelf = self else { + return .complete() + } + + var mergedSessions = strongSelf._state.sessions + for i in 0 ..< mergedSessions.count { + if mergedSessions[i].hash == hash { + mergedSessions.remove(at: i) + break + } + } + + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions) + return .complete() + } + } + + public func removeOther() -> Signal { + return terminateOtherAccountSessions(account: self.account) + |> deliverOnMainQueue + |> mapToSignal { [weak self] _ -> Signal in + guard let strongSelf = self else { + return .complete() + } + + var mergedSessions = strongSelf._state.sessions + for i in (0 ..< mergedSessions.count).reversed() { + if mergedSessions[i].hash != 0 { + mergedSessions.remove(at: i) + break + } + } + + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions) + return .complete() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/AddPeerMember.swift b/submodules/TelegramCore/TelegramCore/AddPeerMember.swift new file mode 100644 index 0000000000..af1aaa3b0f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AddPeerMember.swift @@ -0,0 +1,214 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum AddGroupMemberError { + case generic + case groupFull + case privacy +} + +public func addGroupMember(account: Account, peerId: PeerId, memberId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { + if let group = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.addChatUser(chatId: group.id.id, userId: inputUser, fwdLimit: 100)) + |> mapError { error -> AddGroupMemberError in + switch error.errorDescription { + case "USERS_TOO_MUCH": + return .groupFull + case "USER_PRIVACY_RESTRICTED": + return .privacy + default: + return .generic + } + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return account.postbox.transaction { transaction -> Void in + if let message = result.messages.first, let timestamp = message.timestamp { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedGroupData, let participants = cachedData.participants { + var updatedParticipants = participants.participants + var found = false + for participant in participants.participants { + if participant.peerId == memberId { + found = true + break + } + } + if !found { + updatedParticipants.append(.member(id: memberId, invitedBy: account.peerId, invitedAt: timestamp)) + } + return cachedData.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return cachedData + } + }) + } + } + |> mapError { _ -> AddGroupMemberError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } |> mapError { _ -> AddGroupMemberError in return .generic } |> switchToLatest +} + +public enum AddChannelMemberError { + case generic + case restricted + case limitExceeded + case bot(PeerId) +} + +public func addChannelMember(account: Account, peerId: PeerId, memberId: PeerId) -> Signal<(ChannelParticipant?, RenderedChannelParticipant), AddChannelMemberError> { + return fetchChannelParticipant(account: account, peerId: peerId, participantId: memberId) + |> mapError { error -> AddChannelMemberError in + return .generic + } + |> mapToSignal { currentParticipant -> Signal<(ChannelParticipant?, RenderedChannelParticipant), AddChannelMemberError> in + return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant), AddChannelMemberError> in + if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { + if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { + let updatedParticipant: ChannelParticipant + if let currentParticipant = currentParticipant, case let .member(_, invitedAt, adminInfo, _) = currentParticipant { + updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: invitedAt, adminInfo: adminInfo, banInfo: nil) + } else { + updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: nil, banInfo: nil) + } + return account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: [inputUser])) + |> map { [$0] } + |> `catch` { error -> Signal<[Api.Updates], AddChannelMemberError> in + switch error.errorDescription { + case "USERS_TOO_MUCH": + return .fail(.limitExceeded) + case "USER_PRIVACY_RESTRICTED": + return .fail(.restricted) + case "USER_BOT": + return .fail(.bot(memberId)) + default: + return .fail(.generic) + } + } + |> mapToSignal { result -> Signal<(ChannelParticipant?, RenderedChannelParticipant), AddChannelMemberError> in + for updates in result { + account.stateManager.addUpdates(updates) + } + return account.postbox.transaction { transaction -> (ChannelParticipant?, RenderedChannelParticipant) in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData, let memberCount = cachedData.participantsSummary.memberCount, let kickedCount = cachedData.participantsSummary.kickedCount { + var updatedMemberCount = memberCount + var updatedKickedCount = kickedCount + var wasMember = false + var wasBanned = false + if let currentParticipant = currentParticipant { + switch currentParticipant { + case .creator: + break + case let .member(_, _, _, banInfo): + if let banInfo = banInfo { + wasBanned = true + wasMember = !banInfo.rights.flags.contains(.banReadMessages) + } else { + wasMember = true + } + } + } + if !wasMember { + updatedMemberCount = updatedMemberCount + 1 + } + if wasBanned { + updatedKickedCount = max(0, updatedKickedCount - 1) + } + + return cachedData.withUpdatedParticipantsSummary(cachedData.participantsSummary.withUpdatedMemberCount(updatedMemberCount).withUpdatedKickedCount(updatedKickedCount)) + } else { + return cachedData + } + }) + var peers: [PeerId: Peer] = [:] + var presences: [PeerId: PeerPresence] = [:] + peers[memberPeer.id] = memberPeer + if let presence = transaction.getPeerPresence(peerId: memberPeer.id) { + presences[memberPeer.id] = presence + } + if case let .member(_, _, maybeAdminInfo, maybeBannedInfo) = updatedParticipant { + if let adminInfo = maybeAdminInfo { + if let peer = transaction.getPeer(adminInfo.promotedBy) { + peers[peer.id] = peer + } + } + } + return (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: memberPeer, peers: peers, presences: presences)) + } + |> mapError { _ -> AddChannelMemberError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> AddChannelMemberError in return .generic } + |> switchToLatest + } +} + +public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal { + let signal = account.postbox.transaction { transaction -> Signal in + var memberPeerIds: [PeerId:Peer] = [:] + var inputUsers: [Api.InputUser] = [] + for memberId in memberIds { + if let peer = transaction.getPeer(memberId) { + memberPeerIds[peerId] = peer + if let inputUser = apiInputUser(peer) { + inputUsers.append(inputUser) + } + } + } + + if let peer = transaction.getPeer(peerId), let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { + + let signal = account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: inputUsers)) + |> mapError { error -> AddChannelMemberError in + switch error.errorDescription { + case "USER_PRIVACY_RESTRICTED": + return .restricted + case "USERS_TOO_MUCH": + return .limitExceeded + default: + return .generic + } + } + |> map { result in + account.stateManager.addUpdates(result) + account.viewTracker.forceUpdateCachedPeerData(peerId: peerId) + } + + return signal + } else { + return .single(Void()) + } + + } + |> introduceError(AddChannelMemberError.self) + + return signal + |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/AddressNames.swift b/submodules/TelegramCore/TelegramCore/AddressNames.swift new file mode 100644 index 0000000000..5f7931ac91 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AddressNames.swift @@ -0,0 +1,215 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum AddressNameFormatError { + case startsWithUnderscore + case endsWithUnderscore + case startsWithDigit + case tooShort + case invalidCharacters +} + +public enum AddressNameAvailability: Equatable { + case available + case invalid + case taken +} + +public enum AddressNameDomain { + case account + case peer(PeerId) +} + +public func checkAddressNameFormat(_ value: String, canEmpty: Bool = false) -> AddressNameFormatError? { + var index = 0 + let length = value.count + for char in value { + if char == "_" { + if index == 0 { + return .startsWithUnderscore + } else if index == length - 1 { + return length < 5 ? .tooShort : .endsWithUnderscore + } + } + if index == 0 && char >= "0" && char <= "9" { + return .startsWithDigit + } + if (!((char >= "a" && char <= "z") || (char >= "A" && char <= "Z") || (char >= "0" && char <= "9") || char == "_")) { + return .invalidCharacters + } + index += 1 + } + + if length < 5 && (!canEmpty || length != 0) { + return .tooShort + } + return nil +} + +public func addressNameAvailability(account: Account, domain: AddressNameDomain, name: String) -> Signal { + return account.postbox.transaction { transaction -> Signal in + switch domain { + case .account: + return account.network.request(Api.functions.account.checkUsername(username: name)) + |> map { result -> AddressNameAvailability in + switch result { + case .boolTrue: + return .available + case .boolFalse: + return .taken + } + } + |> `catch` { error -> Signal in + return .single(.invalid) + } + case let .peer(peerId): + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.checkUsername(channel: inputChannel, username: name)) + |> map { result -> AddressNameAvailability in + switch result { + case .boolTrue: + return .available + case .boolFalse: + return .taken + } + } + |> `catch` { error -> Signal in + return .single(.invalid) + } + } else if peerId.namespace == Namespaces.Peer.CloudGroup { + return account.network.request(Api.functions.channels.checkUsername(channel: .inputChannelEmpty, username: name)) + |> map { result -> AddressNameAvailability in + switch result { + case .boolTrue: + return .available + case .boolFalse: + return .taken + } + } + |> `catch` { error -> Signal in + return .single(.invalid) + } + } else { + return .single(.invalid) + } + } + } |> switchToLatest +} + +public enum UpdateAddressNameError { + case generic +} + +public func updateAddressName(account: Account, domain: AddressNameDomain, name: String?) -> Signal { + return account.postbox.transaction { transaction -> Signal in + switch domain { + case .account: + return account.network.request(Api.functions.account.updateUsername(username: name ?? ""), automaticFloodWait: false) + |> mapError { _ -> UpdateAddressNameError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + let user = TelegramUser(user: result) + updatePeers(transaction: transaction, peers: [user], update: { _, updated in + return updated + }) + } |> mapError { _ -> UpdateAddressNameError in return .generic } + } + case let .peer(peerId): + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.updateUsername(channel: inputChannel, username: name ?? ""), automaticFloodWait: false) + |> mapError { _ -> UpdateAddressNameError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if case .boolTrue = result { + if let peer = transaction.getPeer(peerId) as? TelegramChannel { + var updatedPeer = peer.withUpdatedAddressName(name) + if name != nil, let defaultBannedRights = updatedPeer.defaultBannedRights { + updatedPeer = updatedPeer.withUpdatedDefaultBannedRights(TelegramChatBannedRights(flags: defaultBannedRights.flags.union([.banPinMessages, .banChangeInfo]), untilDate: Int32.max)) + } + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + } + } + } |> mapError { _ -> UpdateAddressNameError in return .generic } + } + } else { + return .fail(.generic) + } + } + } |> mapError { _ -> UpdateAddressNameError in return .generic } |> switchToLatest +} + +public func adminedPublicChannels(account: Account) -> Signal<[Peer], NoError> { + return account.network.request(Api.functions.channels.getAdminedPublicChannels()) + |> retryRequest + |> mapToSignal { result -> Signal<[Peer], NoError> in + var peers: [Peer] = [] + switch result { + case let .chats(apiChats): + for chat in apiChats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + peers.append(peer) + } + } + case let .chatsSlice(_, apiChats): + for chat in apiChats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + peers.append(peer) + } + } + } + return account.postbox.transaction { transaction -> [Peer] in + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + return peers + } + } +} + +public enum ChannelAddressNameAssignmentAvailability { + case available + case unknown + case addressNameLimitReached +} + +public func channelAddressNameAssignmentAvailability(account: Account, peerId: PeerId?) -> Signal { + return account.postbox.transaction { transaction -> Signal in + var inputChannel: Api.InputChannel? + if let peerId = peerId { + if let peer = transaction.getPeer(peerId), let channel = apiInputChannel(peer) { + inputChannel = channel + } + } else { + inputChannel = .inputChannelEmpty + } + if let inputChannel = inputChannel { + return account.network.request(Api.functions.channels.checkUsername(channel: inputChannel, username: "username")) + |> map { _ -> ChannelAddressNameAssignmentAvailability in + return .available + } + |> `catch` { error -> Signal in + return .single(.addressNameLimitReached) + } + } else { + return .single(.unknown) + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/Api0.swift b/submodules/TelegramCore/TelegramCore/Api0.swift new file mode 100644 index 0000000000..2ad93261ee --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Api0.swift @@ -0,0 +1,2973 @@ + +fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { + var dict: [Int32 : (BufferReader) -> Any?] = [:] + dict[-1471112230] = { return $0.readInt32() } + dict[570911930] = { return $0.readInt64() } + dict[571523412] = { return $0.readDouble() } + dict[-1255641564] = { return parseString($0) } + dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) } + dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) } + dict[-206066487] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } + dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } + dict[461151667] = { return Api.ChatFull.parse_chatFull($0) } + dict[-1736252138] = { return Api.ChatFull.parse_channelFull($0) } + dict[1465219162] = { return Api.PollResults.parse_pollResults($0) } + dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) } + dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) } + dict[-489233354] = { return Api.ChatParticipant.parse_chatParticipantAdmin($0) } + dict[1567990072] = { return Api.updates.Difference.parse_differenceEmpty($0) } + dict[16030880] = { return Api.updates.Difference.parse_difference($0) } + dict[-1459938943] = { return Api.updates.Difference.parse_differenceSlice($0) } + dict[1258196845] = { return Api.updates.Difference.parse_differenceTooLong($0) } + dict[1462101002] = { return Api.CdnConfig.parse_cdnConfig($0) } + dict[324435594] = { return Api.PageBlock.parse_pageBlockUnsupported($0) } + dict[1890305021] = { return Api.PageBlock.parse_pageBlockTitle($0) } + dict[-1879401953] = { return Api.PageBlock.parse_pageBlockSubtitle($0) } + dict[-1162877472] = { return Api.PageBlock.parse_pageBlockAuthorDate($0) } + dict[-1076861716] = { return Api.PageBlock.parse_pageBlockHeader($0) } + dict[-248793375] = { return Api.PageBlock.parse_pageBlockSubheader($0) } + dict[1182402406] = { return Api.PageBlock.parse_pageBlockParagraph($0) } + dict[-1066346178] = { return Api.PageBlock.parse_pageBlockPreformatted($0) } + dict[1216809369] = { return Api.PageBlock.parse_pageBlockFooter($0) } + dict[-618614392] = { return Api.PageBlock.parse_pageBlockDivider($0) } + dict[-837994576] = { return Api.PageBlock.parse_pageBlockAnchor($0) } + dict[641563686] = { return Api.PageBlock.parse_pageBlockBlockquote($0) } + dict[1329878739] = { return Api.PageBlock.parse_pageBlockPullquote($0) } + dict[972174080] = { return Api.PageBlock.parse_pageBlockCover($0) } + dict[-283684427] = { return Api.PageBlock.parse_pageBlockChannel($0) } + dict[504660880] = { return Api.PageBlock.parse_pageBlockKicker($0) } + dict[-1085412734] = { return Api.PageBlock.parse_pageBlockTable($0) } + dict[391759200] = { return Api.PageBlock.parse_pageBlockPhoto($0) } + dict[2089805750] = { return Api.PageBlock.parse_pageBlockVideo($0) } + dict[-2143067670] = { return Api.PageBlock.parse_pageBlockAudio($0) } + dict[-1468953147] = { return Api.PageBlock.parse_pageBlockEmbed($0) } + dict[-229005301] = { return Api.PageBlock.parse_pageBlockEmbedPost($0) } + dict[1705048653] = { return Api.PageBlock.parse_pageBlockCollage($0) } + dict[52401552] = { return Api.PageBlock.parse_pageBlockSlideshow($0) } + dict[-454524911] = { return Api.PageBlock.parse_pageBlockList($0) } + dict[-1702174239] = { return Api.PageBlock.parse_pageBlockOrderedList($0) } + dict[1987480557] = { return Api.PageBlock.parse_pageBlockDetails($0) } + dict[370236054] = { return Api.PageBlock.parse_pageBlockRelatedArticles($0) } + dict[-1538310410] = { return Api.PageBlock.parse_pageBlockMap($0) } + dict[-614138572] = { return Api.account.TmpPassword.parse_tmpPassword($0) } + dict[-2103600678] = { return Api.SecureRequiredType.parse_secureRequiredType($0) } + dict[41187252] = { return Api.SecureRequiredType.parse_secureRequiredTypeOneOf($0) } + dict[1064139624] = { return Api.JSONValue.parse_jsonNull($0) } + dict[-952869270] = { return Api.JSONValue.parse_jsonBool($0) } + dict[736157604] = { return Api.JSONValue.parse_jsonNumber($0) } + dict[-1222740358] = { return Api.JSONValue.parse_jsonString($0) } + dict[-146520221] = { return Api.JSONValue.parse_jsonArray($0) } + dict[-1715350371] = { return Api.JSONValue.parse_jsonObject($0) } + dict[590459437] = { return Api.Photo.parse_photoEmpty($0) } + dict[-797637467] = { return Api.Photo.parse_photo($0) } + dict[-1683826688] = { return Api.Chat.parse_chatEmpty($0) } + dict[120753115] = { return Api.Chat.parse_chatForbidden($0) } + dict[681420594] = { return Api.Chat.parse_channelForbidden($0) } + dict[1004149726] = { return Api.Chat.parse_chat($0) } + dict[1307772980] = { return Api.Chat.parse_channel($0) } + dict[1202287072] = { return Api.StatsURL.parse_statsURL($0) } + dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) } + dict[-540871282] = { return Api.ChatInvite.parse_chatInvite($0) } + dict[-767099577] = { return Api.AutoDownloadSettings.parse_autoDownloadSettings($0) } + dict[1678812626] = { return Api.StickerSetCovered.parse_stickerSetCovered($0) } + dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) } + dict[1189204285] = { return Api.RecentMeUrl.parse_recentMeUrlUnknown($0) } + dict[-1917045962] = { return Api.RecentMeUrl.parse_recentMeUrlUser($0) } + dict[-1608834311] = { return Api.RecentMeUrl.parse_recentMeUrlChat($0) } + dict[-347535331] = { return Api.RecentMeUrl.parse_recentMeUrlChatInvite($0) } + dict[-1140172836] = { return Api.RecentMeUrl.parse_recentMeUrlStickerSet($0) } + dict[-177282392] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) } + dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) } + dict[-599948721] = { return Api.RichText.parse_textEmpty($0) } + dict[1950782688] = { return Api.RichText.parse_textPlain($0) } + dict[1730456516] = { return Api.RichText.parse_textBold($0) } + dict[-653089380] = { return Api.RichText.parse_textItalic($0) } + dict[-1054465340] = { return Api.RichText.parse_textUnderline($0) } + dict[-1678197867] = { return Api.RichText.parse_textStrike($0) } + dict[1816074681] = { return Api.RichText.parse_textFixed($0) } + dict[1009288385] = { return Api.RichText.parse_textUrl($0) } + dict[-564523562] = { return Api.RichText.parse_textEmail($0) } + dict[2120376535] = { return Api.RichText.parse_textConcat($0) } + dict[-311786236] = { return Api.RichText.parse_textSubscript($0) } + dict[-939827711] = { return Api.RichText.parse_textSuperscript($0) } + dict[55281185] = { return Api.RichText.parse_textMarked($0) } + dict[483104362] = { return Api.RichText.parse_textPhone($0) } + dict[136105807] = { return Api.RichText.parse_textImage($0) } + dict[894777186] = { return Api.RichText.parse_textAnchor($0) } + dict[-302941166] = { return Api.UserFull.parse_userFull($0) } + dict[-292807034] = { return Api.InputChannel.parse_inputChannelEmpty($0) } + dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } + dict[414687501] = { return Api.DcOption.parse_dcOption($0) } + dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) } + dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } + dict[-288727837] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } + dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) } + dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } + dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } + dict[-1590738760] = { return Api.WallPaperSettings.parse_wallPaperSettings($0) } + dict[1152191385] = { return Api.EmojiURL.parse_EmojiURL($0) } + dict[-791039645] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) } + dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) } + dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) } + dict[-1432995067] = { return Api.storage.FileType.parse_fileUnknown($0) } + dict[1086091090] = { return Api.storage.FileType.parse_filePartial($0) } + dict[8322574] = { return Api.storage.FileType.parse_fileJpeg($0) } + dict[-891180321] = { return Api.storage.FileType.parse_fileGif($0) } + dict[172975040] = { return Api.storage.FileType.parse_filePng($0) } + dict[-1373745011] = { return Api.storage.FileType.parse_filePdf($0) } + dict[1384777335] = { return Api.storage.FileType.parse_fileMp3($0) } + dict[1258941372] = { return Api.storage.FileType.parse_fileMov($0) } + dict[-1278304028] = { return Api.storage.FileType.parse_fileMp4($0) } + dict[276907596] = { return Api.storage.FileType.parse_fileWebp($0) } + dict[1338747336] = { return Api.messages.ArchivedStickers.parse_archivedStickers($0) } + dict[406307684] = { return Api.InputEncryptedFile.parse_inputEncryptedFileEmpty($0) } + dict[1690108678] = { return Api.InputEncryptedFile.parse_inputEncryptedFileUploaded($0) } + dict[1511503333] = { return Api.InputEncryptedFile.parse_inputEncryptedFile($0) } + dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) } + dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) } + dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) } + dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) } + dict[-855308010] = { return Api.auth.Authorization.parse_authorization($0) } + dict[-181407105] = { return Api.InputFile.parse_inputFile($0) } + dict[-95482955] = { return Api.InputFile.parse_inputFileBig($0) } + dict[-1649296275] = { return Api.Peer.parse_peerUser($0) } + dict[-1160714821] = { return Api.Peer.parse_peerChat($0) } + dict[-1109531342] = { return Api.Peer.parse_peerChannel($0) } + dict[-1868808300] = { return Api.PaymentRequestedInfo.parse_paymentRequestedInfo($0) } + dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) } + dict[-306628279] = { return Api.UserStatus.parse_userStatusOnline($0) } + dict[9203775] = { return Api.UserStatus.parse_userStatusOffline($0) } + dict[-496024847] = { return Api.UserStatus.parse_userStatusRecently($0) } + dict[129960444] = { return Api.UserStatus.parse_userStatusLastWeek($0) } + dict[2011940674] = { return Api.UserStatus.parse_userStatusLastMonth($0) } + dict[-11252123] = { return Api.Folder.parse_folder($0) } + dict[739712882] = { return Api.Dialog.parse_dialog($0) } + dict[1908216652] = { return Api.Dialog.parse_dialogFolder($0) } + dict[381645902] = { return Api.SendMessageAction.parse_sendMessageTypingAction($0) } + dict[-44119819] = { return Api.SendMessageAction.parse_sendMessageCancelAction($0) } + dict[-1584933265] = { return Api.SendMessageAction.parse_sendMessageRecordVideoAction($0) } + dict[-378127636] = { return Api.SendMessageAction.parse_sendMessageUploadVideoAction($0) } + dict[-718310409] = { return Api.SendMessageAction.parse_sendMessageRecordAudioAction($0) } + dict[-212740181] = { return Api.SendMessageAction.parse_sendMessageUploadAudioAction($0) } + dict[-774682074] = { return Api.SendMessageAction.parse_sendMessageUploadPhotoAction($0) } + dict[-1441998364] = { return Api.SendMessageAction.parse_sendMessageUploadDocumentAction($0) } + dict[393186209] = { return Api.SendMessageAction.parse_sendMessageGeoLocationAction($0) } + dict[1653390447] = { return Api.SendMessageAction.parse_sendMessageChooseContactAction($0) } + dict[-580219064] = { return Api.SendMessageAction.parse_sendMessageGamePlayAction($0) } + dict[-1997373508] = { return Api.SendMessageAction.parse_sendMessageRecordRoundAction($0) } + dict[608050278] = { return Api.SendMessageAction.parse_sendMessageUploadRoundAction($0) } + dict[-1137792208] = { return Api.PrivacyKey.parse_privacyKeyStatusTimestamp($0) } + dict[1343122938] = { return Api.PrivacyKey.parse_privacyKeyChatInvite($0) } + dict[1030105979] = { return Api.PrivacyKey.parse_privacyKeyPhoneCall($0) } + dict[961092808] = { return Api.PrivacyKey.parse_privacyKeyPhoneP2P($0) } + dict[1777096355] = { return Api.PrivacyKey.parse_privacyKeyForwards($0) } + dict[-1777000467] = { return Api.PrivacyKey.parse_privacyKeyProfilePhoto($0) } + dict[-778378131] = { return Api.PrivacyKey.parse_privacyKeyPhoneNumber($0) } + dict[522914557] = { return Api.Update.parse_updateNewMessage($0) } + dict[1318109142] = { return Api.Update.parse_updateMessageID($0) } + dict[-1576161051] = { return Api.Update.parse_updateDeleteMessages($0) } + dict[1548249383] = { return Api.Update.parse_updateUserTyping($0) } + dict[-1704596961] = { return Api.Update.parse_updateChatUserTyping($0) } + dict[125178264] = { return Api.Update.parse_updateChatParticipants($0) } + dict[469489699] = { return Api.Update.parse_updateUserStatus($0) } + dict[-1489818765] = { return Api.Update.parse_updateUserName($0) } + dict[-1791935732] = { return Api.Update.parse_updateUserPhoto($0) } + dict[-1657903163] = { return Api.Update.parse_updateContactLink($0) } + dict[314359194] = { return Api.Update.parse_updateNewEncryptedMessage($0) } + dict[386986326] = { return Api.Update.parse_updateEncryptedChatTyping($0) } + dict[-1264392051] = { return Api.Update.parse_updateEncryption($0) } + dict[956179895] = { return Api.Update.parse_updateEncryptedMessagesRead($0) } + dict[-364179876] = { return Api.Update.parse_updateChatParticipantAdd($0) } + dict[1851755554] = { return Api.Update.parse_updateChatParticipantDelete($0) } + dict[-1906403213] = { return Api.Update.parse_updateDcOptions($0) } + dict[-2131957734] = { return Api.Update.parse_updateUserBlocked($0) } + dict[-1094555409] = { return Api.Update.parse_updateNotifySettings($0) } + dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) } + dict[-298113238] = { return Api.Update.parse_updatePrivacy($0) } + dict[314130811] = { return Api.Update.parse_updateUserPhone($0) } + dict[791617983] = { return Api.Update.parse_updateReadHistoryOutbox($0) } + dict[2139689491] = { return Api.Update.parse_updateWebPage($0) } + dict[1757493555] = { return Api.Update.parse_updateReadMessagesContents($0) } + dict[-352032773] = { return Api.Update.parse_updateChannelTooLong($0) } + dict[-1227598250] = { return Api.Update.parse_updateChannel($0) } + dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) } + dict[-1015733815] = { return Api.Update.parse_updateDeleteChannelMessages($0) } + dict[-1734268085] = { return Api.Update.parse_updateChannelMessageViews($0) } + dict[-1232070311] = { return Api.Update.parse_updateChatParticipantAdmin($0) } + dict[1753886890] = { return Api.Update.parse_updateNewStickerSet($0) } + dict[196268545] = { return Api.Update.parse_updateStickerSetsOrder($0) } + dict[1135492588] = { return Api.Update.parse_updateStickerSets($0) } + dict[-1821035490] = { return Api.Update.parse_updateSavedGifs($0) } + dict[1417832080] = { return Api.Update.parse_updateBotInlineQuery($0) } + dict[239663460] = { return Api.Update.parse_updateBotInlineSend($0) } + dict[457133559] = { return Api.Update.parse_updateEditChannelMessage($0) } + dict[-1738988427] = { return Api.Update.parse_updateChannelPinnedMessage($0) } + dict[-415938591] = { return Api.Update.parse_updateBotCallbackQuery($0) } + dict[-469536605] = { return Api.Update.parse_updateEditMessage($0) } + dict[-103646630] = { return Api.Update.parse_updateInlineBotCallbackQuery($0) } + dict[634833351] = { return Api.Update.parse_updateReadChannelOutbox($0) } + dict[-299124375] = { return Api.Update.parse_updateDraftMessage($0) } + dict[1461528386] = { return Api.Update.parse_updateReadFeaturedStickers($0) } + dict[-1706939360] = { return Api.Update.parse_updateRecentStickers($0) } + dict[-1574314746] = { return Api.Update.parse_updateConfig($0) } + dict[861169551] = { return Api.Update.parse_updatePtsChanged($0) } + dict[1081547008] = { return Api.Update.parse_updateChannelWebPage($0) } + dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) } + dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) } + dict[-523384512] = { return Api.Update.parse_updateBotShippingQuery($0) } + dict[1563376297] = { return Api.Update.parse_updateBotPrecheckoutQuery($0) } + dict[-1425052898] = { return Api.Update.parse_updatePhoneCall($0) } + dict[1442983757] = { return Api.Update.parse_updateLangPack($0) } + dict[-451831443] = { return Api.Update.parse_updateFavedStickers($0) } + dict[-1987495099] = { return Api.Update.parse_updateChannelReadMessagesContents($0) } + dict[1887741886] = { return Api.Update.parse_updateContactsReset($0) } + dict[1893427255] = { return Api.Update.parse_updateChannelAvailableMessages($0) } + dict[-513517117] = { return Api.Update.parse_updateDialogUnreadMark($0) } + dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) } + dict[1279515160] = { return Api.Update.parse_updateUserPinnedMessage($0) } + dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) } + dict[1421875280] = { return Api.Update.parse_updateChatDefaultBannedRights($0) } + dict[-519195831] = { return Api.Update.parse_updateChatPinnedMessage($0) } + dict[422972864] = { return Api.Update.parse_updateFolderPeers($0) } + dict[1852826908] = { return Api.Update.parse_updateDialogPinned($0) } + dict[-99664734] = { return Api.Update.parse_updatePinnedDialogs($0) } + dict[856380452] = { return Api.Update.parse_updateReadChannelInbox($0) } + dict[-1667805217] = { return Api.Update.parse_updateReadHistoryInbox($0) } + dict[1786671974] = { return Api.Update.parse_updatePeerSettings($0) } + dict[1602468195] = { return Api.Update.parse_updateContactLocated($0) } + dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } + dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) } + dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) } + dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } + dict[-471670279] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) } + dict[470789295] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) } + dict[1571450403] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) } + dict[471043349] = { return Api.contacts.Blocked.parse_blocked($0) } + dict[-1878523231] = { return Api.contacts.Blocked.parse_blockedSlice($0) } + dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) } + dict[1684014375] = { return Api.InputDialogPeer.parse_inputDialogPeerFolder($0) } + dict[-994444869] = { return Api.Error.parse_error($0) } + dict[-1150339286] = { return Api.ContactLocated.parse_contactLocated($0) } + dict[-1560655744] = { return Api.KeyboardButton.parse_keyboardButton($0) } + dict[629866245] = { return Api.KeyboardButton.parse_keyboardButtonUrl($0) } + dict[1748655686] = { return Api.KeyboardButton.parse_keyboardButtonCallback($0) } + dict[-1318425559] = { return Api.KeyboardButton.parse_keyboardButtonRequestPhone($0) } + dict[-59151553] = { return Api.KeyboardButton.parse_keyboardButtonRequestGeoLocation($0) } + dict[90744648] = { return Api.KeyboardButton.parse_keyboardButtonSwitchInline($0) } + dict[1358175439] = { return Api.KeyboardButton.parse_keyboardButtonGame($0) } + dict[-1344716869] = { return Api.KeyboardButton.parse_keyboardButtonBuy($0) } + dict[280464681] = { return Api.KeyboardButton.parse_keyboardButtonUrlAuth($0) } + dict[-802258988] = { return Api.KeyboardButton.parse_inputKeyboardButtonUrlAuth($0) } + dict[-748155807] = { return Api.ContactStatus.parse_contactStatus($0) } + dict[1679398724] = { return Api.SecureFile.parse_secureFileEmpty($0) } + dict[-534283678] = { return Api.SecureFile.parse_secureFile($0) } + dict[236446268] = { return Api.PhotoSize.parse_photoSizeEmpty($0) } + dict[2009052699] = { return Api.PhotoSize.parse_photoSize($0) } + dict[-374917894] = { return Api.PhotoSize.parse_photoCachedSize($0) } + dict[-525288402] = { return Api.PhotoSize.parse_photoStrippedSize($0) } + dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) } + dict[-463889475] = { return Api.messages.Stickers.parse_stickers($0) } + dict[1008755359] = { return Api.InlineBotSwitchPM.parse_inlineBotSwitchPM($0) } + dict[223655517] = { return Api.messages.FoundStickerSets.parse_foundStickerSetsNotModified($0) } + dict[1359533640] = { return Api.messages.FoundStickerSets.parse_foundStickerSets($0) } + dict[471437699] = { return Api.account.WallPapers.parse_wallPapersNotModified($0) } + dict[1881892265] = { return Api.account.WallPapers.parse_wallPapers($0) } + dict[1158290442] = { return Api.messages.FoundGifs.parse_foundGifs($0) } + dict[-1132476723] = { return Api.FileLocation.parse_fileLocationToBeDeprecated($0) } + dict[-716006138] = { return Api.Poll.parse_poll($0) } + dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) } + dict[1251338318] = { return Api.InputNotifyPeer.parse_inputNotifyChats($0) } + dict[-1311015810] = { return Api.InputNotifyPeer.parse_inputNotifyBroadcasts($0) } + dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) } + dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) } + dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) } + dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) } + dict[-1268741783] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsAdmins($0) } + dict[-1328445861] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBots($0) } + dict[338142689] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBanned($0) } + dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) } + dict[-1548400251] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsKicked($0) } + dict[-1150621555] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsContacts($0) } + dict[-350980120] = { return Api.WebPage.parse_webPageEmpty($0) } + dict[-981018084] = { return Api.WebPage.parse_webPagePending($0) } + dict[1594340540] = { return Api.WebPage.parse_webPage($0) } + dict[-2054908813] = { return Api.WebPage.parse_webPageNotModified($0) } + dict[1036876423] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageText($0) } + dict[-190472735] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) } + dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) } + dict[864077702] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaAuto($0) } + dict[1098628881] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaVenue($0) } + dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) } + dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) } + dict[-290164953] = { return Api.StickerSet.parse_stickerSet($0) } + dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) } + dict[539045032] = { return Api.photos.Photo.parse_photo($0) } + dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) } + dict[-1419371685] = { return Api.TopPeerCategory.parse_topPeerCategoryBotsPM($0) } + dict[344356834] = { return Api.TopPeerCategory.parse_topPeerCategoryBotsInline($0) } + dict[104314861] = { return Api.TopPeerCategory.parse_topPeerCategoryCorrespondents($0) } + dict[-1122524854] = { return Api.TopPeerCategory.parse_topPeerCategoryGroups($0) } + dict[371037736] = { return Api.TopPeerCategory.parse_topPeerCategoryChannels($0) } + dict[511092620] = { return Api.TopPeerCategory.parse_topPeerCategoryPhoneCalls($0) } + dict[-1472172887] = { return Api.TopPeerCategory.parse_topPeerCategoryForwardUsers($0) } + dict[-68239120] = { return Api.TopPeerCategory.parse_topPeerCategoryForwardChats($0) } + dict[-1219778094] = { return Api.contacts.Contacts.parse_contactsNotModified($0) } + dict[-353862078] = { return Api.contacts.Contacts.parse_contacts($0) } + dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) } + dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) } + dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) } + dict[-1803769784] = { return Api.messages.BotResults.parse_botResults($0) } + dict[1928391342] = { return Api.InputDocument.parse_inputDocumentEmpty($0) } + dict[448771445] = { return Api.InputDocument.parse_inputDocument($0) } + dict[1823064809] = { return Api.PollAnswer.parse_pollAnswer($0) } + dict[2131196633] = { return Api.contacts.ResolvedPeer.parse_resolvedPeer($0) } + dict[-1964327229] = { return Api.SecureData.parse_secureData($0) } + dict[-1771768449] = { return Api.InputMedia.parse_inputMediaEmpty($0) } + dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) } + dict[1212395773] = { return Api.InputMedia.parse_inputMediaGifExternal($0) } + dict[-750828557] = { return Api.InputMedia.parse_inputMediaGame($0) } + dict[-1052959727] = { return Api.InputMedia.parse_inputMediaVenue($0) } + dict[-186607933] = { return Api.InputMedia.parse_inputMediaInvoice($0) } + dict[505969924] = { return Api.InputMedia.parse_inputMediaUploadedPhoto($0) } + dict[1530447553] = { return Api.InputMedia.parse_inputMediaUploadedDocument($0) } + dict[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) } + dict[598418386] = { return Api.InputMedia.parse_inputMediaDocument($0) } + dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) } + dict[-78455655] = { return Api.InputMedia.parse_inputMediaDocumentExternal($0) } + dict[-122978821] = { return Api.InputMedia.parse_inputMediaContact($0) } + dict[112424539] = { return Api.InputMedia.parse_inputMediaPoll($0) } + dict[-833715459] = { return Api.InputMedia.parse_inputMediaGeoLive($0) } + dict[2134579434] = { return Api.InputPeer.parse_inputPeerEmpty($0) } + dict[2107670217] = { return Api.InputPeer.parse_inputPeerSelf($0) } + dict[396093539] = { return Api.InputPeer.parse_inputPeerChat($0) } + dict[2072935910] = { return Api.InputPeer.parse_inputPeerUser($0) } + dict[548253432] = { return Api.InputPeer.parse_inputPeerChannel($0) } + dict[568808380] = { return Api.upload.WebFile.parse_webFile($0) } + dict[-116274796] = { return Api.Contact.parse_contact($0) } + dict[-1078332329] = { return Api.help.PassportConfig.parse_passportConfigNotModified($0) } + dict[-1600596305] = { return Api.help.PassportConfig.parse_passportConfig($0) } + dict[1648543603] = { return Api.FileHash.parse_fileHash($0) } + dict[400266251] = { return Api.BotInlineResult.parse_botInlineMediaResult($0) } + dict[295067450] = { return Api.BotInlineResult.parse_botInlineResult($0) } + dict[911761060] = { return Api.messages.BotCallbackAnswer.parse_botCallbackAnswer($0) } + dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) } + dict[1800845601] = { return Api.payments.PaymentResult.parse_paymentVerficationNeeded($0) } + dict[1694474197] = { return Api.messages.Chats.parse_chats($0) } + dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) } + dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) } + dict[218751099] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowContacts($0) } + dict[407582158] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowAll($0) } + dict[320652927] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowUsers($0) } + dict[195371015] = { return Api.InputPrivacyRule.parse_inputPrivacyValueDisallowContacts($0) } + dict[-697604407] = { return Api.InputPrivacyRule.parse_inputPrivacyValueDisallowAll($0) } + dict[-1877932953] = { return Api.InputPrivacyRule.parse_inputPrivacyValueDisallowUsers($0) } + dict[1283572154] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowChatParticipants($0) } + dict[-668769361] = { return Api.InputPrivacyRule.parse_inputPrivacyValueDisallowChatParticipants($0) } + dict[-1058912715] = { return Api.messages.DhConfig.parse_dhConfigNotModified($0) } + dict[740433629] = { return Api.messages.DhConfig.parse_dhConfig($0) } + dict[-421545947] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeTitle($0) } + dict[1427671598] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeAbout($0) } + dict[1783299128] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeUsername($0) } + dict[460916654] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleInvites($0) } + dict[648939889] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleSignatures($0) } + dict[-370660328] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionUpdatePinned($0) } + dict[1889215493] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionEditMessage($0) } + dict[1121994683] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionDeleteMessage($0) } + dict[405815507] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantJoin($0) } + dict[-124291086] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantLeave($0) } + dict[-484690728] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantInvite($0) } + dict[-422036098] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantToggleBan($0) } + dict[-714643696] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantToggleAdmin($0) } + dict[-1312568665] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeStickerSet($0) } + dict[1599903217] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionTogglePreHistoryHidden($0) } + dict[771095562] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionDefaultBannedRights($0) } + dict[-1895328189] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionStopPoll($0) } + dict[1129042607] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangePhoto($0) } + dict[-1569748965] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeLinkedChat($0) } + dict[-526508104] = { return Api.help.ProxyData.parse_proxyDataEmpty($0) } + dict[737668643] = { return Api.help.ProxyData.parse_proxyDataPromo($0) } + dict[-543777747] = { return Api.auth.ExportedAuthorization.parse_exportedAuthorization($0) } + dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) } + dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) } + dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } + dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } + dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } + dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } + dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) } + dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) } + dict[-438840932] = { return Api.messages.ChatFull.parse_chatFull($0) } + dict[-618540889] = { return Api.InputSecureValue.parse_inputSecureValue($0) } + dict[1722786150] = { return Api.help.DeepLinkInfo.parse_deepLinkInfoEmpty($0) } + dict[1783556146] = { return Api.help.DeepLinkInfo.parse_deepLinkInfo($0) } + dict[-313079300] = { return Api.account.WebAuthorizations.parse_webAuthorizations($0) } + dict[2013922064] = { return Api.help.TermsOfService.parse_termsOfService($0) } + dict[1490799288] = { return Api.ReportReason.parse_inputReportReasonSpam($0) } + dict[505595789] = { return Api.ReportReason.parse_inputReportReasonViolence($0) } + dict[777640226] = { return Api.ReportReason.parse_inputReportReasonPornography($0) } + dict[-512463606] = { return Api.ReportReason.parse_inputReportReasonOther($0) } + dict[-1685456582] = { return Api.ReportReason.parse_inputReportReasonCopyright($0) } + dict[-1376497949] = { return Api.ReportReason.parse_inputReportReasonChildAbuse($0) } + dict[-247351839] = { return Api.InputEncryptedChat.parse_inputEncryptedChat($0) } + dict[-524237339] = { return Api.PageTableRow.parse_pageTableRow($0) } + dict[-40996577] = { return Api.DraftMessage.parse_draftMessage($0) } + dict[453805082] = { return Api.DraftMessage.parse_draftMessageEmpty($0) } + dict[-2128640689] = { return Api.account.SentEmailCode.parse_sentEmailCode($0) } + dict[-1038136962] = { return Api.EncryptedFile.parse_encryptedFileEmpty($0) } + dict[1248893260] = { return Api.EncryptedFile.parse_encryptedFile($0) } + dict[-391902247] = { return Api.SecureValueError.parse_secureValueErrorData($0) } + dict[12467706] = { return Api.SecureValueError.parse_secureValueErrorFrontSide($0) } + dict[-2037765467] = { return Api.SecureValueError.parse_secureValueErrorReverseSide($0) } + dict[-449327402] = { return Api.SecureValueError.parse_secureValueErrorSelfie($0) } + dict[2054162547] = { return Api.SecureValueError.parse_secureValueErrorFile($0) } + dict[1717706985] = { return Api.SecureValueError.parse_secureValueErrorFiles($0) } + dict[-2036501105] = { return Api.SecureValueError.parse_secureValueError($0) } + dict[-1592506512] = { return Api.SecureValueError.parse_secureValueErrorTranslationFile($0) } + dict[878931416] = { return Api.SecureValueError.parse_secureValueErrorTranslationFiles($0) } + dict[-1613493288] = { return Api.NotifyPeer.parse_notifyPeer($0) } + dict[-1261946036] = { return Api.NotifyPeer.parse_notifyUsers($0) } + dict[-1073230141] = { return Api.NotifyPeer.parse_notifyChats($0) } + dict[-703403793] = { return Api.NotifyPeer.parse_notifyBroadcasts($0) } + dict[1335282456] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyStatusTimestamp($0) } + dict[-1107622874] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyChatInvite($0) } + dict[-88417185] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyPhoneCall($0) } + dict[-610373422] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyPhoneP2P($0) } + dict[-1529000952] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyForwards($0) } + dict[1461304012] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyProfilePhoto($0) } + dict[55761658] = { return Api.InputPrivacyKey.parse_inputPrivacyKeyPhoneNumber($0) } + dict[235081943] = { return Api.help.RecentMeUrls.parse_recentMeUrls($0) } + dict[-1606526075] = { return Api.ReplyMarkup.parse_replyKeyboardHide($0) } + dict[-200242528] = { return Api.ReplyMarkup.parse_replyKeyboardForceReply($0) } + dict[889353612] = { return Api.ReplyMarkup.parse_replyKeyboardMarkup($0) } + dict[1218642516] = { return Api.ReplyMarkup.parse_replyInlineMarkup($0) } + dict[1556570557] = { return Api.EmojiKeywordsDifference.parse_emojiKeywordsDifference($0) } + dict[1493171408] = { return Api.HighScore.parse_highScore($0) } + dict[-305282981] = { return Api.TopPeer.parse_topPeer($0) } + dict[411017418] = { return Api.SecureValue.parse_secureValue($0) } + dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) } + dict[1444661369] = { return Api.ContactBlocked.parse_contactBlocked($0) } + dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) } + dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) } + dict[-1188055347] = { return Api.PageListItem.parse_pageListItemText($0) } + dict[635466748] = { return Api.PageListItem.parse_pageListItemBlocks($0) } + dict[-1182234929] = { return Api.InputUser.parse_inputUserEmpty($0) } + dict[-138301121] = { return Api.InputUser.parse_inputUserSelf($0) } + dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } + dict[-1366746132] = { return Api.Page.parse_page($0) } + dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } + dict[157948117] = { return Api.upload.File.parse_file($0) } + dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } + dict[182649427] = { return Api.MessageRange.parse_messageRange($0) } + dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) } + dict[904138920] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultArchive($0) } + dict[856375399] = { return Api.Config.parse_config($0) } + dict[-75283823] = { return Api.TopPeerCategoryPeers.parse_topPeerCategoryPeers($0) } + dict[-1107729093] = { return Api.Game.parse_game($0) } + dict[1605510357] = { return Api.ChatAdminRights.parse_chatAdminRights($0) } + dict[4883767] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoUnknown($0) } + dict[-1141711456] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000($0) } + dict[-2042159726] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoSHA512($0) } + dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) } + dict[-2066640507] = { return Api.messages.AffectedMessages.parse_affectedMessages($0) } + dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) } + dict[772213157] = { return Api.messages.SavedGifs.parse_savedGifs($0) } + dict[-914167110] = { return Api.CdnPublicKey.parse_cdnPublicKey($0) } + dict[53231223] = { return Api.InputGame.parse_inputGameID($0) } + dict[-1020139510] = { return Api.InputGame.parse_inputGameShortName($0) } + dict[-1502174430] = { return Api.InputMessage.parse_inputMessageID($0) } + dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) } + dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) } + dict[-1564789301] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) } + dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) } + dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) } + dict[-1938715001] = { return Api.messages.Messages.parse_messages($0) } + dict[1951620897] = { return Api.messages.Messages.parse_messagesNotModified($0) } + dict[-1725551049] = { return Api.messages.Messages.parse_channelMessages($0) } + dict[-923939298] = { return Api.messages.Messages.parse_messagesSlice($0) } + dict[-1022713000] = { return Api.Invoice.parse_invoice($0) } + dict[-2122045747] = { return Api.PeerSettings.parse_peerSettings($0) } + dict[955951967] = { return Api.auth.SentCode.parse_sentCode($0) } + dict[480546647] = { return Api.InputChatPhoto.parse_inputChatPhotoEmpty($0) } + dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } + dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } + dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } + dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } + dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } + dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($0) } + dict[2027216577] = { return Api.Updates.parse_updateShort($0) } + dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) } + dict[1957577280] = { return Api.Updates.parse_updates($0) } + dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) } + dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) } + dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) } + dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) } + dict[-1557277184] = { return Api.MessageMedia.parse_messageMediaWebPage($0) } + dict[-38694904] = { return Api.MessageMedia.parse_messageMediaGame($0) } + dict[-2074799289] = { return Api.MessageMedia.parse_messageMediaInvoice($0) } + dict[2084316681] = { return Api.MessageMedia.parse_messageMediaGeoLive($0) } + dict[784356159] = { return Api.MessageMedia.parse_messageMediaVenue($0) } + dict[1766936791] = { return Api.MessageMedia.parse_messageMediaPhoto($0) } + dict[-1666158377] = { return Api.MessageMedia.parse_messageMediaDocument($0) } + dict[-873313984] = { return Api.MessageMedia.parse_messageMediaContact($0) } + dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) } + dict[-842892769] = { return Api.PaymentSavedCredentials.parse_paymentSavedCredentialsCard($0) } + dict[1450380236] = { return Api.Null.parse_null($0) } + dict[1923290508] = { return Api.auth.CodeType.parse_codeTypeSms($0) } + dict[1948046307] = { return Api.auth.CodeType.parse_codeTypeCall($0) } + dict[577556219] = { return Api.auth.CodeType.parse_codeTypeFlashCall($0) } + dict[1815593308] = { return Api.DocumentAttribute.parse_documentAttributeImageSize($0) } + dict[297109817] = { return Api.DocumentAttribute.parse_documentAttributeAnimated($0) } + dict[1662637586] = { return Api.DocumentAttribute.parse_documentAttributeSticker($0) } + dict[250621158] = { return Api.DocumentAttribute.parse_documentAttributeVideo($0) } + dict[-1739392570] = { return Api.DocumentAttribute.parse_documentAttributeAudio($0) } + dict[358154344] = { return Api.DocumentAttribute.parse_documentAttributeFilename($0) } + dict[-1744710921] = { return Api.DocumentAttribute.parse_documentAttributeHasStickers($0) } + dict[307276766] = { return Api.account.Authorizations.parse_authorizations($0) } + dict[935395612] = { return Api.ChatPhoto.parse_chatPhotoEmpty($0) } + dict[1197267925] = { return Api.ChatPhoto.parse_chatPhoto($0) } + dict[1869903447] = { return Api.PageCaption.parse_pageCaption($0) } + dict[1062645411] = { return Api.payments.PaymentForm.parse_paymentForm($0) } + dict[1342771681] = { return Api.payments.PaymentReceipt.parse_paymentReceipt($0) } + dict[863093588] = { return Api.messages.PeerDialogs.parse_peerDialogs($0) } + dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) } + dict[-1886646706] = { return Api.UrlAuthResult.parse_urlAuthResultAccepted($0) } + dict[-1445536993] = { return Api.UrlAuthResult.parse_urlAuthResultDefault($0) } + dict[-4838507] = { return Api.InputStickerSet.parse_inputStickerSetEmpty($0) } + dict[-1645763991] = { return Api.InputStickerSet.parse_inputStickerSetID($0) } + dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($0) } + dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) } + dict[-1519637954] = { return Api.updates.State.parse_state($0) } + dict[372165663] = { return Api.FoundGif.parse_foundGif($0) } + dict[-1670052855] = { return Api.FoundGif.parse_foundGifCached($0) } + dict[537022650] = { return Api.User.parse_userEmpty($0) } + dict[773059779] = { return Api.User.parse_user($0) } + dict[-2082087340] = { return Api.Message.parse_messageEmpty($0) } + dict[-1642487306] = { return Api.Message.parse_messageService($0) } + dict[1157215293] = { return Api.Message.parse_message($0) } + dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) } + dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) } + dict[-182231723] = { return Api.InputFileLocation.parse_inputEncryptedFileLocation($0) } + dict[-876089816] = { return Api.InputFileLocation.parse_inputSecureFileLocation($0) } + dict[-539317279] = { return Api.InputFileLocation.parse_inputFileLocation($0) } + dict[1075322878] = { return Api.InputFileLocation.parse_inputPhotoFileLocation($0) } + dict[-1160743548] = { return Api.InputFileLocation.parse_inputDocumentFileLocation($0) } + dict[668375447] = { return Api.InputFileLocation.parse_inputPeerPhotoFileLocation($0) } + dict[230353641] = { return Api.InputFileLocation.parse_inputStickerSetThumb($0) } + dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) } + dict[43446532] = { return Api.GeoPoint.parse_geoPoint($0) } + dict[506920429] = { return Api.InputPhoneCall.parse_inputPhoneCall($0) } + dict[-1551583367] = { return Api.ReceivedNotifyMessage.parse_receivedNotifyMessage($0) } + dict[-57668565] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) } + dict[1061556205] = { return Api.ChatParticipants.parse_chatParticipants($0) } + dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) } + dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) } + dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) } + dict[-905587442] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsAndroidPay($0) } + dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) } + dict[859091184] = { return Api.InputSecureFile.parse_inputSecureFileUploaded($0) } + dict[1399317950] = { return Api.InputSecureFile.parse_inputSecureFile($0) } + dict[512535275] = { return Api.PostAddress.parse_postAddress($0) } + dict[-70073706] = { return Api.InputFolderPeer.parse_inputFolderPeer($0) } + dict[2104790276] = { return Api.DataJSON.parse_dataJSON($0) } + dict[-433014407] = { return Api.InputWallPaper.parse_inputWallPaper($0) } + dict[1913199744] = { return Api.InputWallPaper.parse_inputWallPaperSlug($0) } + dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) } + dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } + dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } + dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } + dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) } + dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) } + dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } + dict[-84416311] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonBusy($0) } + dict[-1910892683] = { return Api.NearestDc.parse_nearestDc($0) } + dict[-1059185703] = { return Api.JSONObjectValue.parse_jsonObjectValue($0) } + dict[-1916114267] = { return Api.photos.Photos.parse_photos($0) } + dict[352657236] = { return Api.photos.Photos.parse_photosSlice($0) } + dict[2010127419] = { return Api.contacts.ImportedContacts.parse_importedContacts($0) } + dict[-1678949555] = { return Api.InputWebDocument.parse_inputWebDocument($0) } + dict[-326966976] = { return Api.phone.PhoneCall.parse_phoneCall($0) } + dict[995769920] = { return Api.ChannelAdminLogEvent.parse_channelAdminLogEvent($0) } + dict[-1132882121] = { return Api.Bool.parse_boolFalse($0) } + dict[-1720552011] = { return Api.Bool.parse_boolTrue($0) } + dict[-892239370] = { return Api.LangPackString.parse_langPackString($0) } + dict[1816636575] = { return Api.LangPackString.parse_langPackStringPluralized($0) } + dict[695856818] = { return Api.LangPackString.parse_langPackStringDeleted($0) } + dict[-1036396922] = { return Api.InputWebFileLocation.parse_inputWebFileLocation($0) } + dict[1430205163] = { return Api.InputWebFileLocation.parse_inputWebFileGeoMessageLocation($0) } + dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) } + dict[-332168592] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) } + dict[398898678] = { return Api.help.Support.parse_support($0) } + dict[1474492012] = { return Api.MessagesFilter.parse_inputMessagesFilterEmpty($0) } + dict[-1777752804] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotos($0) } + dict[-1614803355] = { return Api.MessagesFilter.parse_inputMessagesFilterVideo($0) } + dict[1458172132] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotoVideo($0) } + dict[-648121413] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotoVideoDocuments($0) } + dict[-1629621880] = { return Api.MessagesFilter.parse_inputMessagesFilterDocument($0) } + dict[2129714567] = { return Api.MessagesFilter.parse_inputMessagesFilterUrl($0) } + dict[-3644025] = { return Api.MessagesFilter.parse_inputMessagesFilterGif($0) } + dict[1358283666] = { return Api.MessagesFilter.parse_inputMessagesFilterVoice($0) } + dict[928101534] = { return Api.MessagesFilter.parse_inputMessagesFilterMusic($0) } + dict[975236280] = { return Api.MessagesFilter.parse_inputMessagesFilterChatPhotos($0) } + dict[-2134272152] = { return Api.MessagesFilter.parse_inputMessagesFilterPhoneCalls($0) } + dict[2054952868] = { return Api.MessagesFilter.parse_inputMessagesFilterRoundVoice($0) } + dict[-1253451181] = { return Api.MessagesFilter.parse_inputMessagesFilterRoundVideo($0) } + dict[-1040652646] = { return Api.MessagesFilter.parse_inputMessagesFilterMyMentions($0) } + dict[1187706024] = { return Api.MessagesFilter.parse_inputMessagesFilterMyMentionsUnread($0) } + dict[-419271411] = { return Api.MessagesFilter.parse_inputMessagesFilterGeo($0) } + dict[-530392189] = { return Api.MessagesFilter.parse_inputMessagesFilterContacts($0) } + dict[364538944] = { return Api.messages.Dialogs.parse_dialogs($0) } + dict[1910543603] = { return Api.messages.Dialogs.parse_dialogsSlice($0) } + dict[-253500010] = { return Api.messages.Dialogs.parse_dialogsNotModified($0) } + dict[-709641735] = { return Api.EmojiKeyword.parse_emojiKeyword($0) } + dict[594408994] = { return Api.EmojiKeyword.parse_emojiKeywordDeleted($0) } + dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) } + dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) } + dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) } + dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) } + dict[982505656] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) } + dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) } + dict[-1970903652] = { return Api.BotInlineMessage.parse_botInlineMessageMediaVenue($0) } + dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) } + dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) } + dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) } + dict[-209768682] = { return Api.messages.FavedStickers.parse_favedStickers($0) } + dict[1776236393] = { return Api.ExportedChatInvite.parse_chatInviteEmpty($0) } + dict[-64092740] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } + dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } + dict[-1392388579] = { return Api.Authorization.parse_authorization($0) } + dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) } + dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) } + dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) } + dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) } + dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } + dict[-1658158621] = { return Api.SecureValueType.parse_secureValueTypePersonalDetails($0) } + dict[1034709504] = { return Api.SecureValueType.parse_secureValueTypePassport($0) } + dict[115615172] = { return Api.SecureValueType.parse_secureValueTypeDriverLicense($0) } + dict[-1596951477] = { return Api.SecureValueType.parse_secureValueTypeIdentityCard($0) } + dict[-1717268701] = { return Api.SecureValueType.parse_secureValueTypeInternalPassport($0) } + dict[-874308058] = { return Api.SecureValueType.parse_secureValueTypeAddress($0) } + dict[-63531698] = { return Api.SecureValueType.parse_secureValueTypeUtilityBill($0) } + dict[-1995211763] = { return Api.SecureValueType.parse_secureValueTypeBankStatement($0) } + dict[-1954007928] = { return Api.SecureValueType.parse_secureValueTypeRentalAgreement($0) } + dict[-1713143702] = { return Api.SecureValueType.parse_secureValueTypePassportRegistration($0) } + dict[-368907213] = { return Api.SecureValueType.parse_secureValueTypeTemporaryRegistration($0) } + dict[-1289704741] = { return Api.SecureValueType.parse_secureValueTypePhone($0) } + dict[-1908627474] = { return Api.SecureValueType.parse_secureValueTypeEmail($0) } + dict[-732254058] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoUnknown($0) } + dict[982592842] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow($0) } + dict[-1390001672] = { return Api.account.Password.parse_password($0) } + dict[-1462213465] = { return Api.InputBotInlineResult.parse_inputBotInlineResultPhoto($0) } + dict[-459324] = { return Api.InputBotInlineResult.parse_inputBotInlineResultDocument($0) } + dict[1336154098] = { return Api.InputBotInlineResult.parse_inputBotInlineResultGame($0) } + dict[-2000710887] = { return Api.InputBotInlineResult.parse_inputBotInlineResult($0) } + dict[1352683077] = { return Api.account.PrivacyRules.parse_privacyRules($0) } + dict[-123988] = { return Api.PrivacyRule.parse_privacyValueAllowContacts($0) } + dict[1698855810] = { return Api.PrivacyRule.parse_privacyValueAllowAll($0) } + dict[1297858060] = { return Api.PrivacyRule.parse_privacyValueAllowUsers($0) } + dict[-125240806] = { return Api.PrivacyRule.parse_privacyValueDisallowContacts($0) } + dict[-1955338397] = { return Api.PrivacyRule.parse_privacyValueDisallowAll($0) } + dict[209668535] = { return Api.PrivacyRule.parse_privacyValueDisallowUsers($0) } + dict[415136107] = { return Api.PrivacyRule.parse_privacyValueAllowChatParticipants($0) } + dict[-1397881200] = { return Api.PrivacyRule.parse_privacyValueDisallowChatParticipants($0) } + dict[-1230047312] = { return Api.MessageAction.parse_messageActionEmpty($0) } + dict[-1503425638] = { return Api.MessageAction.parse_messageActionChatCreate($0) } + dict[-1247687078] = { return Api.MessageAction.parse_messageActionChatEditTitle($0) } + dict[2144015272] = { return Api.MessageAction.parse_messageActionChatEditPhoto($0) } + dict[-1780220945] = { return Api.MessageAction.parse_messageActionChatDeletePhoto($0) } + dict[1217033015] = { return Api.MessageAction.parse_messageActionChatAddUser($0) } + dict[-1297179892] = { return Api.MessageAction.parse_messageActionChatDeleteUser($0) } + dict[-123931160] = { return Api.MessageAction.parse_messageActionChatJoinedByLink($0) } + dict[-1781355374] = { return Api.MessageAction.parse_messageActionChannelCreate($0) } + dict[1371385889] = { return Api.MessageAction.parse_messageActionChatMigrateTo($0) } + dict[-1336546578] = { return Api.MessageAction.parse_messageActionChannelMigrateFrom($0) } + dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) } + dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) } + dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) } + dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) } + dict[1080663248] = { return Api.MessageAction.parse_messageActionPaymentSent($0) } + dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) } + dict[1200788123] = { return Api.MessageAction.parse_messageActionScreenshotTaken($0) } + dict[-85549226] = { return Api.MessageAction.parse_messageActionCustomAction($0) } + dict[-1410748418] = { return Api.MessageAction.parse_messageActionBotAllowed($0) } + dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) } + dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) } + dict[-202219658] = { return Api.MessageAction.parse_messageActionContactSignUp($0) } + dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) } + dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) } + dict[-2014659757] = { return Api.PhoneCall.parse_phoneCallRequested($0) } + dict[-1719909046] = { return Api.PhoneCall.parse_phoneCallAccepted($0) } + dict[-2025673089] = { return Api.PhoneCall.parse_phoneCall($0) } + dict[1355435489] = { return Api.PhoneCall.parse_phoneCallDiscarded($0) } + dict[-483352705] = { return Api.help.TermsOfServiceUpdate.parse_termsOfServiceUpdateEmpty($0) } + dict[686618977] = { return Api.help.TermsOfServiceUpdate.parse_termsOfServiceUpdate($0) } + dict[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) } + dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) } + dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) } + dict[1599050311] = { return Api.ContactLink.parse_contactLinkUnknown($0) } + dict[-17968211] = { return Api.ContactLink.parse_contactLinkNone($0) } + dict[-721239344] = { return Api.ContactLink.parse_contactLinkContact($0) } + dict[-104284986] = { return Api.WebDocument.parse_webDocumentNoProxy($0) } + dict[475467473] = { return Api.WebDocument.parse_webDocument($0) } + dict[-1290580579] = { return Api.contacts.Found.parse_found($0) } + dict[-368018716] = { return Api.ChannelAdminLogEventsFilter.parse_channelAdminLogEventsFilter($0) } + dict[1889961234] = { return Api.PeerNotifySettings.parse_peerNotifySettingsEmpty($0) } + dict[-1353671392] = { return Api.PeerNotifySettings.parse_peerNotifySettings($0) } + dict[-1995686519] = { return Api.InputBotInlineMessageID.parse_inputBotInlineMessageID($0) } + dict[-1282352120] = { return Api.PageRelatedArticle.parse_pageRelatedArticle($0) } + dict[313694676] = { return Api.StickerPack.parse_stickerPack($0) } + dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) } + dict[-321430132] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } + dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) } + dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } + dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } + dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) } + dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) } + dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) } + dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) } + dict[-1148011883] = { return Api.MessageEntity.parse_messageEntityUnknown($0) } + dict[-100378723] = { return Api.MessageEntity.parse_messageEntityMention($0) } + dict[1868782349] = { return Api.MessageEntity.parse_messageEntityHashtag($0) } + dict[1827637959] = { return Api.MessageEntity.parse_messageEntityBotCommand($0) } + dict[1859134776] = { return Api.MessageEntity.parse_messageEntityUrl($0) } + dict[1692693954] = { return Api.MessageEntity.parse_messageEntityEmail($0) } + dict[-1117713463] = { return Api.MessageEntity.parse_messageEntityBold($0) } + dict[-2106619040] = { return Api.MessageEntity.parse_messageEntityItalic($0) } + dict[681706865] = { return Api.MessageEntity.parse_messageEntityCode($0) } + dict[1938967520] = { return Api.MessageEntity.parse_messageEntityPre($0) } + dict[1990644519] = { return Api.MessageEntity.parse_messageEntityTextUrl($0) } + dict[892193368] = { return Api.MessageEntity.parse_messageEntityMentionName($0) } + dict[546203849] = { return Api.MessageEntity.parse_inputMessageEntityMentionName($0) } + dict[-1687559349] = { return Api.MessageEntity.parse_messageEntityPhone($0) } + dict[1280209983] = { return Api.MessageEntity.parse_messageEntityCashtag($0) } + dict[-1672577397] = { return Api.MessageEntity.parse_messageEntityUnderline($0) } + dict[-1090087980] = { return Api.MessageEntity.parse_messageEntityStrike($0) } + dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) } + dict[483901197] = { return Api.InputPhoto.parse_inputPhotoEmpty($0) } + dict[1001634122] = { return Api.InputPhoto.parse_inputPhoto($0) } + dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) } + dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) } + dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) } + dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) } + dict[-1073693790] = { return Api.auth.SentCodeType.parse_sentCodeTypeSms($0) } + dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) } + dict[-1425815847] = { return Api.auth.SentCodeType.parse_sentCodeTypeFlashCall($0) } + dict[1577484359] = { return Api.PageListOrderedItem.parse_pageListOrderedItemText($0) } + dict[-1730311882] = { return Api.PageListOrderedItem.parse_pageListOrderedItemBlocks($0) } + dict[-1417756512] = { return Api.EncryptedChat.parse_encryptedChatEmpty($0) } + dict[1006044124] = { return Api.EncryptedChat.parse_encryptedChatWaiting($0) } + dict[-931638658] = { return Api.EncryptedChat.parse_encryptedChatRequested($0) } + dict[-94974410] = { return Api.EncryptedChat.parse_encryptedChat($0) } + dict[332848423] = { return Api.EncryptedChat.parse_encryptedChatDiscarded($0) } + dict[922273905] = { return Api.Document.parse_documentEmpty($0) } + dict[-1683841855] = { return Api.Document.parse_document($0) } + dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } + dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } + dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } + return dict +}() + +struct Api { + static func parse(_ buffer: Buffer) -> Any? { + let reader = BufferReader(buffer) + if let signature = reader.readInt32() { + return parse(reader, signature: signature) + } + return nil + } + + static func parse(_ reader: BufferReader, signature: Int32) -> Any? { + if let parser = parsers[signature] { + return parser(reader) + } + else { + Logger.shared.log("TL", "Type constructor \(String(signature, radix: 16, uppercase: false)) not found") + return nil + } + } + + static func parseVector(_ reader: BufferReader, elementSignature: Int32, elementType: T.Type) -> [T]? { + if let count = reader.readInt32() { + var array = [T]() + var i: Int32 = 0 + while i < count { + var signature = elementSignature + if elementSignature == 0 { + if let unboxedSignature = reader.readInt32() { + signature = unboxedSignature + } + else { + return nil + } + } + if elementType == Buffer.self { + if let item = parseBytes(reader) as? T { + array.append(item) + } else { + return nil + } + } else { + if let item = Api.parse(reader, signature: signature) as? T { + array.append(item) + } + else { + return nil + } + } + i += 1 + } + return array + } + return nil + } + + static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) { + switch object { + case let _1 as Api.messages.StickerSet: + _1.serialize(buffer, boxed) + case let _1 as Api.InputGeoPoint: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.ValidatedRequestedInfo: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatFull: + _1.serialize(buffer, boxed) + case let _1 as Api.PollResults: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatParticipant: + _1.serialize(buffer, boxed) + case let _1 as Api.updates.Difference: + _1.serialize(buffer, boxed) + case let _1 as Api.CdnConfig: + _1.serialize(buffer, boxed) + case let _1 as Api.PageBlock: + _1.serialize(buffer, boxed) + case let _1 as Api.account.TmpPassword: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureRequiredType: + _1.serialize(buffer, boxed) + case let _1 as Api.JSONValue: + _1.serialize(buffer, boxed) + case let _1 as Api.Photo: + _1.serialize(buffer, boxed) + case let _1 as Api.Chat: + _1.serialize(buffer, boxed) + case let _1 as Api.StatsURL: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatInvite: + _1.serialize(buffer, boxed) + case let _1 as Api.AutoDownloadSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.StickerSetCovered: + _1.serialize(buffer, boxed) + case let _1 as Api.RecentMeUrl: + _1.serialize(buffer, boxed) + case let _1 as Api.channels.ChannelParticipants: + _1.serialize(buffer, boxed) + case let _1 as Api.RichText: + _1.serialize(buffer, boxed) + case let _1 as Api.UserFull: + _1.serialize(buffer, boxed) + case let _1 as Api.InputChannel: + _1.serialize(buffer, boxed) + case let _1 as Api.DcOption: + _1.serialize(buffer, boxed) + case let _1 as Api.PollAnswerVoters: + _1.serialize(buffer, boxed) + case let _1 as Api.account.PasswordSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.LangPackLanguage: + _1.serialize(buffer, boxed) + case let _1 as Api.help.AppUpdate: + _1.serialize(buffer, boxed) + case let _1 as Api.LangPackDifference: + _1.serialize(buffer, boxed) + case let _1 as Api.WallPaperSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.EmojiURL: + _1.serialize(buffer, boxed) + case let _1 as Api.channels.ChannelParticipant: + _1.serialize(buffer, boxed) + case let _1 as Api.InputCheckPasswordSRP: + _1.serialize(buffer, boxed) + case let _1 as Api.storage.FileType: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.ArchivedStickers: + _1.serialize(buffer, boxed) + case let _1 as Api.InputEncryptedFile: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.SentEncryptedMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.ExportedMessageLink: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.Authorization: + _1.serialize(buffer, boxed) + case let _1 as Api.InputFile: + _1.serialize(buffer, boxed) + case let _1 as Api.Peer: + _1.serialize(buffer, boxed) + case let _1 as Api.PaymentRequestedInfo: + _1.serialize(buffer, boxed) + case let _1 as Api.UserStatus: + _1.serialize(buffer, boxed) + case let _1 as Api.Folder: + _1.serialize(buffer, boxed) + case let _1 as Api.Dialog: + _1.serialize(buffer, boxed) + case let _1 as Api.SendMessageAction: + _1.serialize(buffer, boxed) + case let _1 as Api.PrivacyKey: + _1.serialize(buffer, boxed) + case let _1 as Api.Update: + _1.serialize(buffer, boxed) + case let _1 as Api.PopularContact: + _1.serialize(buffer, boxed) + case let _1 as Api.FolderPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelParticipant: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.Blocked: + _1.serialize(buffer, boxed) + case let _1 as Api.InputDialogPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.Error: + _1.serialize(buffer, boxed) + case let _1 as Api.ContactLocated: + _1.serialize(buffer, boxed) + case let _1 as Api.KeyboardButton: + _1.serialize(buffer, boxed) + case let _1 as Api.ContactStatus: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureFile: + _1.serialize(buffer, boxed) + case let _1 as Api.PhotoSize: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.Stickers: + _1.serialize(buffer, boxed) + case let _1 as Api.InlineBotSwitchPM: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.FoundStickerSets: + _1.serialize(buffer, boxed) + case let _1 as Api.account.WallPapers: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.FoundGifs: + _1.serialize(buffer, boxed) + case let _1 as Api.FileLocation: + _1.serialize(buffer, boxed) + case let _1 as Api.Poll: + _1.serialize(buffer, boxed) + case let _1 as Api.InputNotifyPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.EncryptedMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelParticipantsFilter: + _1.serialize(buffer, boxed) + case let _1 as Api.WebPage: + _1.serialize(buffer, boxed) + case let _1 as Api.InputBotInlineMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.KeyboardButtonRow: + _1.serialize(buffer, boxed) + case let _1 as Api.StickerSet: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureSecretSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.photos.Photo: + _1.serialize(buffer, boxed) + case let _1 as Api.InputContact: + _1.serialize(buffer, boxed) + case let _1 as Api.TopPeerCategory: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.Contacts: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelMessagesFilter: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.PasswordRecovery: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.BotResults: + _1.serialize(buffer, boxed) + case let _1 as Api.InputDocument: + _1.serialize(buffer, boxed) + case let _1 as Api.PollAnswer: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.ResolvedPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureData: + _1.serialize(buffer, boxed) + case let _1 as Api.InputMedia: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.upload.WebFile: + _1.serialize(buffer, boxed) + case let _1 as Api.Contact: + _1.serialize(buffer, boxed) + case let _1 as Api.help.PassportConfig: + _1.serialize(buffer, boxed) + case let _1 as Api.FileHash: + _1.serialize(buffer, boxed) + case let _1 as Api.BotInlineResult: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.BotCallbackAnswer: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.PaymentResult: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.Chats: + _1.serialize(buffer, boxed) + case let _1 as Api.InputSingleMedia: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPrivacyRule: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.DhConfig: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelAdminLogEventAction: + _1.serialize(buffer, boxed) + case let _1 as Api.help.ProxyData: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.ExportedAuthorization: + _1.serialize(buffer, boxed) + case let _1 as Api.SecurePlainData: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.AffectedHistory: + _1.serialize(buffer, boxed) + case let _1 as Api.account.PasswordInputSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.PageTableCell: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatBannedRights: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.MessageEditData: + _1.serialize(buffer, boxed) + case let _1 as Api.LabeledPrice: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.ChatFull: + _1.serialize(buffer, boxed) + case let _1 as Api.InputSecureValue: + _1.serialize(buffer, boxed) + case let _1 as Api.help.DeepLinkInfo: + _1.serialize(buffer, boxed) + case let _1 as Api.account.WebAuthorizations: + _1.serialize(buffer, boxed) + case let _1 as Api.help.TermsOfService: + _1.serialize(buffer, boxed) + case let _1 as Api.ReportReason: + _1.serialize(buffer, boxed) + case let _1 as Api.InputEncryptedChat: + _1.serialize(buffer, boxed) + case let _1 as Api.PageTableRow: + _1.serialize(buffer, boxed) + case let _1 as Api.DraftMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.account.SentEmailCode: + _1.serialize(buffer, boxed) + case let _1 as Api.EncryptedFile: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureValueError: + _1.serialize(buffer, boxed) + case let _1 as Api.NotifyPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPrivacyKey: + _1.serialize(buffer, boxed) + case let _1 as Api.help.RecentMeUrls: + _1.serialize(buffer, boxed) + case let _1 as Api.ReplyMarkup: + _1.serialize(buffer, boxed) + case let _1 as Api.EmojiKeywordsDifference: + _1.serialize(buffer, boxed) + case let _1 as Api.HighScore: + _1.serialize(buffer, boxed) + case let _1 as Api.TopPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureValue: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureValueHash: + _1.serialize(buffer, boxed) + case let _1 as Api.ContactBlocked: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.SearchCounter: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.CheckedPhone: + _1.serialize(buffer, boxed) + case let _1 as Api.PageListItem: + _1.serialize(buffer, boxed) + case let _1 as Api.InputUser: + _1.serialize(buffer, boxed) + case let _1 as Api.Page: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureCredentialsEncrypted: + _1.serialize(buffer, boxed) + case let _1 as Api.upload.File: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageRange: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.StickerSetInstallResult: + _1.serialize(buffer, boxed) + case let _1 as Api.Config: + _1.serialize(buffer, boxed) + case let _1 as Api.TopPeerCategoryPeers: + _1.serialize(buffer, boxed) + case let _1 as Api.Game: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatAdminRights: + _1.serialize(buffer, boxed) + case let _1 as Api.SecurePasswordKdfAlgo: + _1.serialize(buffer, boxed) + case let _1 as Api.BotCommand: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.AffectedMessages: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.SavedGifs: + _1.serialize(buffer, boxed) + case let _1 as Api.CdnPublicKey: + _1.serialize(buffer, boxed) + case let _1 as Api.InputGame: + _1.serialize(buffer, boxed) + case let _1 as Api.InputMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.PhoneCallProtocol: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageFwdAuthor: + _1.serialize(buffer, boxed) + case let _1 as Api.WallPaper: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.Messages: + _1.serialize(buffer, boxed) + case let _1 as Api.Invoice: + _1.serialize(buffer, boxed) + case let _1 as Api.PeerSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.SentCode: + _1.serialize(buffer, boxed) + case let _1 as Api.InputChatPhoto: + _1.serialize(buffer, boxed) + case let _1 as Api.PaymentCharge: + _1.serialize(buffer, boxed) + case let _1 as Api.Updates: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageMedia: + _1.serialize(buffer, boxed) + case let _1 as Api.PaymentSavedCredentials: + _1.serialize(buffer, boxed) + case let _1 as Api.Null: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.CodeType: + _1.serialize(buffer, boxed) + case let _1 as Api.DocumentAttribute: + _1.serialize(buffer, boxed) + case let _1 as Api.account.Authorizations: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatPhoto: + _1.serialize(buffer, boxed) + case let _1 as Api.PageCaption: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.PaymentForm: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.PaymentReceipt: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.PeerDialogs: + _1.serialize(buffer, boxed) + case let _1 as Api.UrlAuthResult: + _1.serialize(buffer, boxed) + case let _1 as Api.InputStickerSet: + _1.serialize(buffer, boxed) + case let _1 as Api.BotInfo: + _1.serialize(buffer, boxed) + case let _1 as Api.updates.State: + _1.serialize(buffer, boxed) + case let _1 as Api.FoundGif: + _1.serialize(buffer, boxed) + case let _1 as Api.User: + _1.serialize(buffer, boxed) + case let _1 as Api.Message: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.RecentStickers: + _1.serialize(buffer, boxed) + case let _1 as Api.InputFileLocation: + _1.serialize(buffer, boxed) + case let _1 as Api.GeoPoint: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPhoneCall: + _1.serialize(buffer, boxed) + case let _1 as Api.ReceivedNotifyMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatParticipants: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPaymentCredentials: + _1.serialize(buffer, boxed) + case let _1 as Api.ShippingOption: + _1.serialize(buffer, boxed) + case let _1 as Api.InputSecureFile: + _1.serialize(buffer, boxed) + case let _1 as Api.PostAddress: + _1.serialize(buffer, boxed) + case let _1 as Api.InputFolderPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.DataJSON: + _1.serialize(buffer, boxed) + case let _1 as Api.InputWallPaper: + _1.serialize(buffer, boxed) + case let _1 as Api.InputStickeredMedia: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.FeaturedStickers: + _1.serialize(buffer, boxed) + case let _1 as Api.PhoneCallDiscardReason: + _1.serialize(buffer, boxed) + case let _1 as Api.NearestDc: + _1.serialize(buffer, boxed) + case let _1 as Api.JSONObjectValue: + _1.serialize(buffer, boxed) + case let _1 as Api.photos.Photos: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.ImportedContacts: + _1.serialize(buffer, boxed) + case let _1 as Api.InputWebDocument: + _1.serialize(buffer, boxed) + case let _1 as Api.phone.PhoneCall: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelAdminLogEvent: + _1.serialize(buffer, boxed) + case let _1 as Api.Bool: + _1.serialize(buffer, boxed) + case let _1 as Api.LangPackString: + _1.serialize(buffer, boxed) + case let _1 as Api.InputWebFileLocation: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageFwdHeader: + _1.serialize(buffer, boxed) + case let _1 as Api.help.Support: + _1.serialize(buffer, boxed) + case let _1 as Api.MessagesFilter: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.Dialogs: + _1.serialize(buffer, boxed) + case let _1 as Api.EmojiKeyword: + _1.serialize(buffer, boxed) + case let _1 as Api.upload.CdnFile: + _1.serialize(buffer, boxed) + case let _1 as Api.help.InviteText: + _1.serialize(buffer, boxed) + case let _1 as Api.BotInlineMessage: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPeerNotifySettings: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.FavedStickers: + _1.serialize(buffer, boxed) + case let _1 as Api.ExportedChatInvite: + _1.serialize(buffer, boxed) + case let _1 as Api.account.AuthorizationForm: + _1.serialize(buffer, boxed) + case let _1 as Api.Authorization: + _1.serialize(buffer, boxed) + case let _1 as Api.MaskCoords: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.AllStickers: + _1.serialize(buffer, boxed) + case let _1 as Api.PhoneConnection: + _1.serialize(buffer, boxed) + case let _1 as Api.AccountDaysTTL: + _1.serialize(buffer, boxed) + case let _1 as Api.SecureValueType: + _1.serialize(buffer, boxed) + case let _1 as Api.PasswordKdfAlgo: + _1.serialize(buffer, boxed) + case let _1 as Api.account.Password: + _1.serialize(buffer, boxed) + case let _1 as Api.InputBotInlineResult: + _1.serialize(buffer, boxed) + case let _1 as Api.account.PrivacyRules: + _1.serialize(buffer, boxed) + case let _1 as Api.PrivacyRule: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageAction: + _1.serialize(buffer, boxed) + case let _1 as Api.PhoneCall: + _1.serialize(buffer, boxed) + case let _1 as Api.help.TermsOfServiceUpdate: + _1.serialize(buffer, boxed) + case let _1 as Api.account.AutoDownloadSettings: + _1.serialize(buffer, boxed) + case let _1 as Api.DialogPeer: + _1.serialize(buffer, boxed) + case let _1 as Api.ContactLink: + _1.serialize(buffer, boxed) + case let _1 as Api.WebDocument: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.Found: + _1.serialize(buffer, boxed) + case let _1 as Api.ChannelAdminLogEventsFilter: + _1.serialize(buffer, boxed) + case let _1 as Api.PeerNotifySettings: + _1.serialize(buffer, boxed) + case let _1 as Api.InputBotInlineMessageID: + _1.serialize(buffer, boxed) + case let _1 as Api.PageRelatedArticle: + _1.serialize(buffer, boxed) + case let _1 as Api.StickerPack: + _1.serialize(buffer, boxed) + case let _1 as Api.UserProfilePhoto: + _1.serialize(buffer, boxed) + case let _1 as Api.payments.SavedInfo: + _1.serialize(buffer, boxed) + case let _1 as Api.updates.ChannelDifference: + _1.serialize(buffer, boxed) + case let _1 as Api.channels.AdminLogResults: + _1.serialize(buffer, boxed) + case let _1 as Api.ChatOnlines: + _1.serialize(buffer, boxed) + case let _1 as Api.InputAppEvent: + _1.serialize(buffer, boxed) + case let _1 as Api.MessageEntity: + _1.serialize(buffer, boxed) + case let _1 as Api.InputPhoto: + _1.serialize(buffer, boxed) + case let _1 as Api.contacts.TopPeers: + _1.serialize(buffer, boxed) + case let _1 as Api.auth.SentCodeType: + _1.serialize(buffer, boxed) + case let _1 as Api.PageListOrderedItem: + _1.serialize(buffer, boxed) + case let _1 as Api.EncryptedChat: + _1.serialize(buffer, boxed) + case let _1 as Api.Document: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.HighScores: + _1.serialize(buffer, boxed) + case let _1 as Api.WebAuthorization: + _1.serialize(buffer, boxed) + case let _1 as Api.ImportedContact: + _1.serialize(buffer, boxed) + default: + break + } + } + +} +extension Api { +struct messages { + enum StickerSet: TypeConstructorDescription { + case stickerSet(set: Api.StickerSet, packs: [Api.StickerPack], documents: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickerSet(let set, let packs, let documents): + if boxed { + buffer.appendInt32(-1240849242) + } + set.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(packs.count)) + for item in packs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(documents.count)) + for item in documents { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickerSet(let set, let packs, let documents): + return ("stickerSet", [("set", set), ("packs", packs), ("documents", documents)]) + } + } + + static func parse_stickerSet(_ reader: BufferReader) -> StickerSet? { + var _1: Api.StickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StickerSet + } + var _2: [Api.StickerPack]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerPack.self) + } + var _3: [Api.Document]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.StickerSet.stickerSet(set: _1!, packs: _2!, documents: _3!) + } + else { + return nil + } + } + + } + enum ArchivedStickers: TypeConstructorDescription { + case archivedStickers(count: Int32, sets: [Api.StickerSetCovered]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .archivedStickers(let count, let sets): + if boxed { + buffer.appendInt32(1338747336) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sets.count)) + for item in sets { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .archivedStickers(let count, let sets): + return ("archivedStickers", [("count", count), ("sets", sets)]) + } + } + + static func parse_archivedStickers(_ reader: BufferReader) -> ArchivedStickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerSetCovered]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.ArchivedStickers.archivedStickers(count: _1!, sets: _2!) + } + else { + return nil + } + } + + } + enum SentEncryptedMessage: TypeConstructorDescription { + case sentEncryptedMessage(date: Int32) + case sentEncryptedFile(date: Int32, file: Api.EncryptedFile) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sentEncryptedMessage(let date): + if boxed { + buffer.appendInt32(1443858741) + } + serializeInt32(date, buffer: buffer, boxed: false) + break + case .sentEncryptedFile(let date, let file): + if boxed { + buffer.appendInt32(-1802240206) + } + serializeInt32(date, buffer: buffer, boxed: false) + file.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sentEncryptedMessage(let date): + return ("sentEncryptedMessage", [("date", date)]) + case .sentEncryptedFile(let date, let file): + return ("sentEncryptedFile", [("date", date), ("file", file)]) + } + } + + static func parse_sentEncryptedMessage(_ reader: BufferReader) -> SentEncryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.SentEncryptedMessage.sentEncryptedMessage(date: _1!) + } + else { + return nil + } + } + static func parse_sentEncryptedFile(_ reader: BufferReader) -> SentEncryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.EncryptedFile? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.EncryptedFile + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.SentEncryptedMessage.sentEncryptedFile(date: _1!, file: _2!) + } + else { + return nil + } + } + + } + enum Stickers: TypeConstructorDescription { + case stickersNotModified + case stickers(hash: Int32, stickers: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickersNotModified: + if boxed { + buffer.appendInt32(-244016606) + } + + break + case .stickers(let hash, let stickers): + if boxed { + buffer.appendInt32(-463889475) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickers.count)) + for item in stickers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickersNotModified: + return ("stickersNotModified", []) + case .stickers(let hash, let stickers): + return ("stickers", [("hash", hash), ("stickers", stickers)]) + } + } + + static func parse_stickersNotModified(_ reader: BufferReader) -> Stickers? { + return Api.messages.Stickers.stickersNotModified + } + static func parse_stickers(_ reader: BufferReader) -> Stickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Document]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.Stickers.stickers(hash: _1!, stickers: _2!) + } + else { + return nil + } + } + + } + enum FoundStickerSets: TypeConstructorDescription { + case foundStickerSetsNotModified + case foundStickerSets(hash: Int32, sets: [Api.StickerSetCovered]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .foundStickerSetsNotModified: + if boxed { + buffer.appendInt32(223655517) + } + + break + case .foundStickerSets(let hash, let sets): + if boxed { + buffer.appendInt32(1359533640) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sets.count)) + for item in sets { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .foundStickerSetsNotModified: + return ("foundStickerSetsNotModified", []) + case .foundStickerSets(let hash, let sets): + return ("foundStickerSets", [("hash", hash), ("sets", sets)]) + } + } + + static func parse_foundStickerSetsNotModified(_ reader: BufferReader) -> FoundStickerSets? { + return Api.messages.FoundStickerSets.foundStickerSetsNotModified + } + static func parse_foundStickerSets(_ reader: BufferReader) -> FoundStickerSets? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerSetCovered]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.FoundStickerSets.foundStickerSets(hash: _1!, sets: _2!) + } + else { + return nil + } + } + + } + enum FoundGifs: TypeConstructorDescription { + case foundGifs(nextOffset: Int32, results: [Api.FoundGif]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .foundGifs(let nextOffset, let results): + if boxed { + buffer.appendInt32(1158290442) + } + serializeInt32(nextOffset, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(results.count)) + for item in results { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .foundGifs(let nextOffset, let results): + return ("foundGifs", [("nextOffset", nextOffset), ("results", results)]) + } + } + + static func parse_foundGifs(_ reader: BufferReader) -> FoundGifs? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.FoundGif]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.FoundGif.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.FoundGifs.foundGifs(nextOffset: _1!, results: _2!) + } + else { + return nil + } + } + + } + enum BotResults: TypeConstructorDescription { + case botResults(flags: Int32, queryId: Int64, nextOffset: String?, switchPm: Api.InlineBotSwitchPM?, results: [Api.BotInlineResult], cacheTime: Int32, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botResults(let flags, let queryId, let nextOffset, let switchPm, let results, let cacheTime, let users): + if boxed { + buffer.appendInt32(-1803769784) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {switchPm!.serialize(buffer, true)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(results.count)) + for item in results { + item.serialize(buffer, true) + } + serializeInt32(cacheTime, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botResults(let flags, let queryId, let nextOffset, let switchPm, let results, let cacheTime, let users): + return ("botResults", [("flags", flags), ("queryId", queryId), ("nextOffset", nextOffset), ("switchPm", switchPm), ("results", results), ("cacheTime", cacheTime), ("users", users)]) + } + } + + static func parse_botResults(_ reader: BufferReader) -> BotResults? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: Api.InlineBotSwitchPM? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InlineBotSwitchPM + } } + var _5: [Api.BotInlineResult]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInlineResult.self) + } + var _6: Int32? + _6 = reader.readInt32() + var _7: [Api.User]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.messages.BotResults.botResults(flags: _1!, queryId: _2!, nextOffset: _3, switchPm: _4, results: _5!, cacheTime: _6!, users: _7!) + } + else { + return nil + } + } + + } + enum BotCallbackAnswer: TypeConstructorDescription { + case botCallbackAnswer(flags: Int32, message: String?, url: String?, cacheTime: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botCallbackAnswer(let flags, let message, let url, let cacheTime): + if boxed { + buffer.appendInt32(911761060) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(message!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + serializeInt32(cacheTime, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botCallbackAnswer(let flags, let message, let url, let cacheTime): + return ("botCallbackAnswer", [("flags", flags), ("message", message), ("url", url), ("cacheTime", cacheTime)]) + } + } + + static func parse_botCallbackAnswer(_ reader: BufferReader) -> BotCallbackAnswer? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: String? + if Int(_1!) & Int(1 << 2) != 0 {_3 = parseString(reader) } + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.BotCallbackAnswer.botCallbackAnswer(flags: _1!, message: _2, url: _3, cacheTime: _4!) + } + else { + return nil + } + } + + } + enum Chats: TypeConstructorDescription { + case chats(chats: [Api.Chat]) + case chatsSlice(count: Int32, chats: [Api.Chat]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chats(let chats): + if boxed { + buffer.appendInt32(1694474197) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + break + case .chatsSlice(let count, let chats): + if boxed { + buffer.appendInt32(-1663561404) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chats(let chats): + return ("chats", [("chats", chats)]) + case .chatsSlice(let count, let chats): + return ("chatsSlice", [("count", count), ("chats", chats)]) + } + } + + static func parse_chats(_ reader: BufferReader) -> Chats? { + var _1: [Api.Chat]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.messages.Chats.chats(chats: _1!) + } + else { + return nil + } + } + static func parse_chatsSlice(_ reader: BufferReader) -> Chats? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.Chats.chatsSlice(count: _1!, chats: _2!) + } + else { + return nil + } + } + + } + enum DhConfig: TypeConstructorDescription { + case dhConfigNotModified(random: Buffer) + case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dhConfigNotModified(let random): + if boxed { + buffer.appendInt32(-1058912715) + } + serializeBytes(random, buffer: buffer, boxed: false) + break + case .dhConfig(let g, let p, let version, let random): + if boxed { + buffer.appendInt32(740433629) + } + serializeInt32(g, buffer: buffer, boxed: false) + serializeBytes(p, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + serializeBytes(random, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dhConfigNotModified(let random): + return ("dhConfigNotModified", [("random", random)]) + case .dhConfig(let g, let p, let version, let random): + return ("dhConfig", [("g", g), ("p", p), ("version", version), ("random", random)]) + } + } + + static func parse_dhConfigNotModified(_ reader: BufferReader) -> DhConfig? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.messages.DhConfig.dhConfigNotModified(random: _1!) + } + else { + return nil + } + } + static func parse_dhConfig(_ reader: BufferReader) -> DhConfig? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.DhConfig.dhConfig(g: _1!, p: _2!, version: _3!, random: _4!) + } + else { + return nil + } + } + + } + enum AffectedHistory: TypeConstructorDescription { + case affectedHistory(pts: Int32, ptsCount: Int32, offset: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .affectedHistory(let pts, let ptsCount, let offset): + if boxed { + buffer.appendInt32(-1269012015) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .affectedHistory(let pts, let ptsCount, let offset): + return ("affectedHistory", [("pts", pts), ("ptsCount", ptsCount), ("offset", offset)]) + } + } + + static func parse_affectedHistory(_ reader: BufferReader) -> AffectedHistory? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.AffectedHistory.affectedHistory(pts: _1!, ptsCount: _2!, offset: _3!) + } + else { + return nil + } + } + + } + enum MessageEditData: TypeConstructorDescription { + case messageEditData(flags: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageEditData(let flags): + if boxed { + buffer.appendInt32(649453030) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageEditData(let flags): + return ("messageEditData", [("flags", flags)]) + } + } + + static func parse_messageEditData(_ reader: BufferReader) -> MessageEditData? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.MessageEditData.messageEditData(flags: _1!) + } + else { + return nil + } + } + + } + enum ChatFull: TypeConstructorDescription { + case chatFull(fullChat: Api.ChatFull, chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatFull(let fullChat, let chats, let users): + if boxed { + buffer.appendInt32(-438840932) + } + fullChat.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatFull(let fullChat, let chats, let users): + return ("chatFull", [("fullChat", fullChat), ("chats", chats), ("users", users)]) + } + } + + static func parse_chatFull(_ reader: BufferReader) -> ChatFull? { + var _1: Api.ChatFull? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChatFull + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.ChatFull.chatFull(fullChat: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum SearchCounter: TypeConstructorDescription { + case searchCounter(flags: Int32, filter: Api.MessagesFilter, count: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .searchCounter(let flags, let filter, let count): + if boxed { + buffer.appendInt32(-398136321) + } + serializeInt32(flags, buffer: buffer, boxed: false) + filter.serialize(buffer, true) + serializeInt32(count, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .searchCounter(let flags, let filter, let count): + return ("searchCounter", [("flags", flags), ("filter", filter), ("count", count)]) + } + } + + static func parse_searchCounter(_ reader: BufferReader) -> SearchCounter? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.MessagesFilter? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.MessagesFilter + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.SearchCounter.searchCounter(flags: _1!, filter: _2!, count: _3!) + } + else { + return nil + } + } + + } + enum StickerSetInstallResult: TypeConstructorDescription { + case stickerSetInstallResultSuccess + case stickerSetInstallResultArchive(sets: [Api.StickerSetCovered]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickerSetInstallResultSuccess: + if boxed { + buffer.appendInt32(946083368) + } + + break + case .stickerSetInstallResultArchive(let sets): + if boxed { + buffer.appendInt32(904138920) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sets.count)) + for item in sets { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickerSetInstallResultSuccess: + return ("stickerSetInstallResultSuccess", []) + case .stickerSetInstallResultArchive(let sets): + return ("stickerSetInstallResultArchive", [("sets", sets)]) + } + } + + static func parse_stickerSetInstallResultSuccess(_ reader: BufferReader) -> StickerSetInstallResult? { + return Api.messages.StickerSetInstallResult.stickerSetInstallResultSuccess + } + static func parse_stickerSetInstallResultArchive(_ reader: BufferReader) -> StickerSetInstallResult? { + var _1: [Api.StickerSetCovered]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.messages.StickerSetInstallResult.stickerSetInstallResultArchive(sets: _1!) + } + else { + return nil + } + } + + } + enum AffectedMessages: TypeConstructorDescription { + case affectedMessages(pts: Int32, ptsCount: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .affectedMessages(let pts, let ptsCount): + if boxed { + buffer.appendInt32(-2066640507) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .affectedMessages(let pts, let ptsCount): + return ("affectedMessages", [("pts", pts), ("ptsCount", ptsCount)]) + } + } + + static func parse_affectedMessages(_ reader: BufferReader) -> AffectedMessages? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.AffectedMessages.affectedMessages(pts: _1!, ptsCount: _2!) + } + else { + return nil + } + } + + } + enum SavedGifs: TypeConstructorDescription { + case savedGifsNotModified + case savedGifs(hash: Int32, gifs: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .savedGifsNotModified: + if boxed { + buffer.appendInt32(-402498398) + } + + break + case .savedGifs(let hash, let gifs): + if boxed { + buffer.appendInt32(772213157) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(gifs.count)) + for item in gifs { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .savedGifsNotModified: + return ("savedGifsNotModified", []) + case .savedGifs(let hash, let gifs): + return ("savedGifs", [("hash", hash), ("gifs", gifs)]) + } + } + + static func parse_savedGifsNotModified(_ reader: BufferReader) -> SavedGifs? { + return Api.messages.SavedGifs.savedGifsNotModified + } + static func parse_savedGifs(_ reader: BufferReader) -> SavedGifs? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Document]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.SavedGifs.savedGifs(hash: _1!, gifs: _2!) + } + else { + return nil + } + } + + } + enum Messages: TypeConstructorDescription { + case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case messagesNotModified(count: Int32) + case channelMessages(flags: Int32, pts: Int32, count: Int32, messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messages(let messages, let chats, let users): + if boxed { + buffer.appendInt32(-1938715001) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .messagesNotModified(let count): + if boxed { + buffer.appendInt32(1951620897) + } + serializeInt32(count, buffer: buffer, boxed: false) + break + case .channelMessages(let flags, let pts, let count, let messages, let chats, let users): + if boxed { + buffer.appendInt32(-1725551049) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .messagesSlice(let flags, let count, let nextRate, let messages, let chats, let users): + if boxed { + buffer.appendInt32(-923939298) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextRate!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messages(let messages, let chats, let users): + return ("messages", [("messages", messages), ("chats", chats), ("users", users)]) + case .messagesNotModified(let count): + return ("messagesNotModified", [("count", count)]) + case .channelMessages(let flags, let pts, let count, let messages, let chats, let users): + return ("channelMessages", [("flags", flags), ("pts", pts), ("count", count), ("messages", messages), ("chats", chats), ("users", users)]) + case .messagesSlice(let flags, let count, let nextRate, let messages, let chats, let users): + return ("messagesSlice", [("flags", flags), ("count", count), ("nextRate", nextRate), ("messages", messages), ("chats", chats), ("users", users)]) + } + } + + static func parse_messages(_ reader: BufferReader) -> Messages? { + var _1: [Api.Message]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.Messages.messages(messages: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + static func parse_messagesNotModified(_ reader: BufferReader) -> Messages? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.Messages.messagesNotModified(count: _1!) + } + else { + return nil + } + } + static func parse_channelMessages(_ reader: BufferReader) -> Messages? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: [Api.Message]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _5: [Api.Chat]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _6: [Api.User]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.messages.Messages.channelMessages(flags: _1!, pts: _2!, count: _3!, messages: _4!, chats: _5!, users: _6!) + } + else { + return nil + } + } + static func parse_messagesSlice(_ reader: BufferReader) -> Messages? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + var _4: [Api.Message]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _5: [Api.Chat]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _6: [Api.User]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.messages.Messages.messagesSlice(flags: _1!, count: _2!, nextRate: _3, messages: _4!, chats: _5!, users: _6!) + } + else { + return nil + } + } + + } + enum PeerDialogs: TypeConstructorDescription { + case peerDialogs(dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], state: Api.updates.State) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .peerDialogs(let dialogs, let messages, let chats, let users, let state): + if boxed { + buffer.appendInt32(863093588) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + state.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .peerDialogs(let dialogs, let messages, let chats, let users, let state): + return ("peerDialogs", [("dialogs", dialogs), ("messages", messages), ("chats", chats), ("users", users), ("state", state)]) + } + } + + static func parse_peerDialogs(_ reader: BufferReader) -> PeerDialogs? { + var _1: [Api.Dialog]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) + } + var _2: [Api.Message]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _5: Api.updates.State? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.updates.State + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.messages.PeerDialogs.peerDialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!, state: _5!) + } + else { + return nil + } + } + + } + enum RecentStickers: TypeConstructorDescription { + case recentStickersNotModified + case recentStickers(hash: Int32, packs: [Api.StickerPack], stickers: [Api.Document], dates: [Int32]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .recentStickersNotModified: + if boxed { + buffer.appendInt32(186120336) + } + + break + case .recentStickers(let hash, let packs, let stickers, let dates): + if boxed { + buffer.appendInt32(586395571) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(packs.count)) + for item in packs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickers.count)) + for item in stickers { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dates.count)) + for item in dates { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .recentStickersNotModified: + return ("recentStickersNotModified", []) + case .recentStickers(let hash, let packs, let stickers, let dates): + return ("recentStickers", [("hash", hash), ("packs", packs), ("stickers", stickers), ("dates", dates)]) + } + } + + static func parse_recentStickersNotModified(_ reader: BufferReader) -> RecentStickers? { + return Api.messages.RecentStickers.recentStickersNotModified + } + static func parse_recentStickers(_ reader: BufferReader) -> RecentStickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerPack]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerPack.self) + } + var _3: [Api.Document]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + var _4: [Int32]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.RecentStickers.recentStickers(hash: _1!, packs: _2!, stickers: _3!, dates: _4!) + } + else { + return nil + } + } + + } + enum FeaturedStickers: TypeConstructorDescription { + case featuredStickersNotModified + case featuredStickers(hash: Int32, sets: [Api.StickerSetCovered], unread: [Int64]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .featuredStickersNotModified: + if boxed { + buffer.appendInt32(82699215) + } + + break + case .featuredStickers(let hash, let sets, let unread): + if boxed { + buffer.appendInt32(-123893531) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sets.count)) + for item in sets { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(unread.count)) + for item in unread { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .featuredStickersNotModified: + return ("featuredStickersNotModified", []) + case .featuredStickers(let hash, let sets, let unread): + return ("featuredStickers", [("hash", hash), ("sets", sets), ("unread", unread)]) + } + } + + static func parse_featuredStickersNotModified(_ reader: BufferReader) -> FeaturedStickers? { + return Api.messages.FeaturedStickers.featuredStickersNotModified + } + static func parse_featuredStickers(_ reader: BufferReader) -> FeaturedStickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerSetCovered]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + } + var _3: [Int64]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.FeaturedStickers.featuredStickers(hash: _1!, sets: _2!, unread: _3!) + } + else { + return nil + } + } + + } + enum Dialogs: TypeConstructorDescription { + case dialogs(dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case dialogsSlice(count: Int32, dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case dialogsNotModified(count: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dialogs(let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(364538944) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(1910543603) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .dialogsNotModified(let count): + if boxed { + buffer.appendInt32(-253500010) + } + serializeInt32(count, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dialogs(let dialogs, let messages, let chats, let users): + return ("dialogs", [("dialogs", dialogs), ("messages", messages), ("chats", chats), ("users", users)]) + case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): + return ("dialogsSlice", [("count", count), ("dialogs", dialogs), ("messages", messages), ("chats", chats), ("users", users)]) + case .dialogsNotModified(let count): + return ("dialogsNotModified", [("count", count)]) + } + } + + static func parse_dialogs(_ reader: BufferReader) -> Dialogs? { + var _1: [Api.Dialog]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) + } + var _2: [Api.Message]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.Dialogs.dialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + static func parse_dialogsSlice(_ reader: BufferReader) -> Dialogs? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Dialog]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) + } + var _3: [Api.Message]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _4: [Api.Chat]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.messages.Dialogs.dialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!) + } + else { + return nil + } + } + static func parse_dialogsNotModified(_ reader: BufferReader) -> Dialogs? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.Dialogs.dialogsNotModified(count: _1!) + } + else { + return nil + } + } + + } + enum FavedStickers: TypeConstructorDescription { + case favedStickersNotModified + case favedStickers(hash: Int32, packs: [Api.StickerPack], stickers: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .favedStickersNotModified: + if boxed { + buffer.appendInt32(-1634752813) + } + + break + case .favedStickers(let hash, let packs, let stickers): + if boxed { + buffer.appendInt32(-209768682) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(packs.count)) + for item in packs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickers.count)) + for item in stickers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .favedStickersNotModified: + return ("favedStickersNotModified", []) + case .favedStickers(let hash, let packs, let stickers): + return ("favedStickers", [("hash", hash), ("packs", packs), ("stickers", stickers)]) + } + } + + static func parse_favedStickersNotModified(_ reader: BufferReader) -> FavedStickers? { + return Api.messages.FavedStickers.favedStickersNotModified + } + static func parse_favedStickers(_ reader: BufferReader) -> FavedStickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerPack]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerPack.self) + } + var _3: [Api.Document]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.FavedStickers.favedStickers(hash: _1!, packs: _2!, stickers: _3!) + } + else { + return nil + } + } + + } + enum AllStickers: TypeConstructorDescription { + case allStickersNotModified + case allStickers(hash: Int32, sets: [Api.StickerSet]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .allStickersNotModified: + if boxed { + buffer.appendInt32(-395967805) + } + + break + case .allStickers(let hash, let sets): + if boxed { + buffer.appendInt32(-302170017) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sets.count)) + for item in sets { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .allStickersNotModified: + return ("allStickersNotModified", []) + case .allStickers(let hash, let sets): + return ("allStickers", [("hash", hash), ("sets", sets)]) + } + } + + static func parse_allStickersNotModified(_ reader: BufferReader) -> AllStickers? { + return Api.messages.AllStickers.allStickersNotModified + } + static func parse_allStickers(_ reader: BufferReader) -> AllStickers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.StickerSet]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSet.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.AllStickers.allStickers(hash: _1!, sets: _2!) + } + else { + return nil + } + } + + } + enum HighScores: TypeConstructorDescription { + case highScores(scores: [Api.HighScore], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .highScores(let scores, let users): + if boxed { + buffer.appendInt32(-1707344487) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(scores.count)) + for item in scores { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .highScores(let scores, let users): + return ("highScores", [("scores", scores), ("users", users)]) + } + } + + static func parse_highScores(_ reader: BufferReader) -> HighScores? { + var _1: [Api.HighScore]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.HighScore.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.HighScores.highScores(scores: _1!, users: _2!) + } + else { + return nil + } + } + + } +} +} diff --git a/submodules/TelegramCore/TelegramCore/Api1.swift b/submodules/TelegramCore/TelegramCore/Api1.swift new file mode 100644 index 0000000000..98bc5ae237 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Api1.swift @@ -0,0 +1,19296 @@ +extension Api { + enum InputGeoPoint: TypeConstructorDescription { + case inputGeoPointEmpty + case inputGeoPoint(lat: Double, long: Double) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputGeoPointEmpty: + if boxed { + buffer.appendInt32(-457104426) + } + + break + case .inputGeoPoint(let lat, let long): + if boxed { + buffer.appendInt32(-206066487) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputGeoPointEmpty: + return ("inputGeoPointEmpty", []) + case .inputGeoPoint(let lat, let long): + return ("inputGeoPoint", [("lat", lat), ("long", long)]) + } + } + + static func parse_inputGeoPointEmpty(_ reader: BufferReader) -> InputGeoPoint? { + return Api.InputGeoPoint.inputGeoPointEmpty + } + static func parse_inputGeoPoint(_ reader: BufferReader) -> InputGeoPoint? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputGeoPoint.inputGeoPoint(lat: _1!, long: _2!) + } + else { + return nil + } + } + + } + enum ChatFull: TypeConstructorDescription { + case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?) + case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, pts: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId): + if boxed { + buffer.appendInt32(461151667) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(about, buffer: buffer, boxed: false) + participants.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)} + notifySettings.serialize(buffer, true) + exportedInvite.serialize(buffer, true) + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(botInfo!.count)) + for item in botInfo! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + break + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let pts): + if boxed { + buffer.appendInt32(-1736252138) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(about, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(participantsCount!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(adminsCount!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(kickedCount!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(bannedCount!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 13) != 0 {serializeInt32(onlineCount!, buffer: buffer, boxed: false)} + serializeInt32(readInboxMaxId, buffer: buffer, boxed: false) + serializeInt32(readOutboxMaxId, buffer: buffer, boxed: false) + serializeInt32(unreadCount, buffer: buffer, boxed: false) + chatPhoto.serialize(buffer, true) + notifySettings.serialize(buffer, true) + exportedInvite.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(botInfo.count)) + for item in botInfo { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(migratedFromChatId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(migratedFromMaxId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 8) != 0 {stickerset!.serialize(buffer, true)} + if Int(flags) & Int(1 << 9) != 0 {serializeInt32(availableMinId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 13) != 0 {serializeInt32(linkedChatId!, buffer: buffer, boxed: false)} + serializeInt32(pts, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId): + return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId)]) + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let pts): + return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("pts", pts)]) + } + } + + static func parse_chatFull(_ reader: BufferReader) -> ChatFull? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Api.ChatParticipants? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ChatParticipants + } + var _5: Api.Photo? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _6: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + var _7: Api.ExportedChatInvite? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite + } + var _8: [Api.BotInfo]? + if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self) + } } + var _9: Int32? + if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() } + var _10: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7!, botInfo: _8, pinnedMsgId: _9, folderId: _10) + } + else { + return nil + } + } + static func parse_channelFull(_ reader: BufferReader) -> ChatFull? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() } + var _5: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } + var _6: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt32() } + var _7: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_7 = reader.readInt32() } + var _8: Int32? + if Int(_1!) & Int(1 << 13) != 0 {_8 = reader.readInt32() } + var _9: Int32? + _9 = reader.readInt32() + var _10: Int32? + _10 = reader.readInt32() + var _11: Int32? + _11 = reader.readInt32() + var _12: Api.Photo? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _13: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + var _14: Api.ExportedChatInvite? + if let signature = reader.readInt32() { + _14 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite + } + var _15: [Api.BotInfo]? + if let _ = reader.readInt32() { + _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self) + } + var _16: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_16 = reader.readInt32() } + var _17: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_17 = reader.readInt32() } + var _18: Int32? + if Int(_1!) & Int(1 << 5) != 0 {_18 = reader.readInt32() } + var _19: Api.StickerSet? + if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() { + _19 = Api.parse(reader, signature: signature) as? Api.StickerSet + } } + var _20: Int32? + if Int(_1!) & Int(1 << 9) != 0 {_20 = reader.readInt32() } + var _21: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_21 = reader.readInt32() } + var _22: Int32? + if Int(_1!) & Int(1 << 13) != 0 {_22 = reader.readInt32() } + var _23: Int32? + _23 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 13) == 0) || _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + let _c16 = (Int(_1!) & Int(1 << 4) == 0) || _16 != nil + let _c17 = (Int(_1!) & Int(1 << 4) == 0) || _17 != nil + let _c18 = (Int(_1!) & Int(1 << 5) == 0) || _18 != nil + let _c19 = (Int(_1!) & Int(1 << 8) == 0) || _19 != nil + let _c20 = (Int(_1!) & Int(1 << 9) == 0) || _20 != nil + let _c21 = (Int(_1!) & Int(1 << 11) == 0) || _21 != nil + let _c22 = (Int(_1!) & Int(1 << 13) == 0) || _22 != nil + let _c23 = _23 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 { + return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, pts: _23!) + } + else { + return nil + } + } + + } + enum PollResults: TypeConstructorDescription { + case pollResults(flags: Int32, results: [Api.PollAnswerVoters]?, totalVoters: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pollResults(let flags, let results, let totalVoters): + if boxed { + buffer.appendInt32(1465219162) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(results!.count)) + for item in results! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(totalVoters!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pollResults(let flags, let results, let totalVoters): + return ("pollResults", [("flags", flags), ("results", results), ("totalVoters", totalVoters)]) + } + } + + static func parse_pollResults(_ reader: BufferReader) -> PollResults? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.PollAnswerVoters]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PollAnswerVoters.self) + } } + var _3: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.PollResults.pollResults(flags: _1!, results: _2, totalVoters: _3) + } + else { + return nil + } + } + + } + enum ChatParticipant: TypeConstructorDescription { + case chatParticipant(userId: Int32, inviterId: Int32, date: Int32) + case chatParticipantCreator(userId: Int32) + case chatParticipantAdmin(userId: Int32, inviterId: Int32, date: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatParticipant(let userId, let inviterId, let date): + if boxed { + buffer.appendInt32(-925415106) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(inviterId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .chatParticipantCreator(let userId): + if boxed { + buffer.appendInt32(-636267638) + } + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .chatParticipantAdmin(let userId, let inviterId, let date): + if boxed { + buffer.appendInt32(-489233354) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(inviterId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatParticipant(let userId, let inviterId, let date): + return ("chatParticipant", [("userId", userId), ("inviterId", inviterId), ("date", date)]) + case .chatParticipantCreator(let userId): + return ("chatParticipantCreator", [("userId", userId)]) + case .chatParticipantAdmin(let userId, let inviterId, let date): + return ("chatParticipantAdmin", [("userId", userId), ("inviterId", inviterId), ("date", date)]) + } + } + + static func parse_chatParticipant(_ reader: BufferReader) -> ChatParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChatParticipant.chatParticipant(userId: _1!, inviterId: _2!, date: _3!) + } + else { + return nil + } + } + static func parse_chatParticipantCreator(_ reader: BufferReader) -> ChatParticipant? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ChatParticipant.chatParticipantCreator(userId: _1!) + } + else { + return nil + } + } + static func parse_chatParticipantAdmin(_ reader: BufferReader) -> ChatParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChatParticipant.chatParticipantAdmin(userId: _1!, inviterId: _2!, date: _3!) + } + else { + return nil + } + } + + } + enum CdnConfig: TypeConstructorDescription { + case cdnConfig(publicKeys: [Api.CdnPublicKey]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .cdnConfig(let publicKeys): + if boxed { + buffer.appendInt32(1462101002) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(publicKeys.count)) + for item in publicKeys { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .cdnConfig(let publicKeys): + return ("cdnConfig", [("publicKeys", publicKeys)]) + } + } + + static func parse_cdnConfig(_ reader: BufferReader) -> CdnConfig? { + var _1: [Api.CdnPublicKey]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.CdnPublicKey.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.CdnConfig.cdnConfig(publicKeys: _1!) + } + else { + return nil + } + } + + } + indirect enum PageBlock: TypeConstructorDescription { + case pageBlockUnsupported + case pageBlockTitle(text: Api.RichText) + case pageBlockSubtitle(text: Api.RichText) + case pageBlockAuthorDate(author: Api.RichText, publishedDate: Int32) + case pageBlockHeader(text: Api.RichText) + case pageBlockSubheader(text: Api.RichText) + case pageBlockParagraph(text: Api.RichText) + case pageBlockPreformatted(text: Api.RichText, language: String) + case pageBlockFooter(text: Api.RichText) + case pageBlockDivider + case pageBlockAnchor(name: String) + case pageBlockBlockquote(text: Api.RichText, caption: Api.RichText) + case pageBlockPullquote(text: Api.RichText, caption: Api.RichText) + case pageBlockCover(cover: Api.PageBlock) + case pageBlockChannel(channel: Api.Chat) + case pageBlockKicker(text: Api.RichText) + case pageBlockTable(flags: Int32, title: Api.RichText, rows: [Api.PageTableRow]) + case pageBlockPhoto(flags: Int32, photoId: Int64, caption: Api.PageCaption, url: String?, webpageId: Int64?) + case pageBlockVideo(flags: Int32, videoId: Int64, caption: Api.PageCaption) + case pageBlockAudio(audioId: Int64, caption: Api.PageCaption) + case pageBlockEmbed(flags: Int32, url: String?, html: String?, posterPhotoId: Int64?, w: Int32?, h: Int32?, caption: Api.PageCaption) + case pageBlockEmbedPost(url: String, webpageId: Int64, authorPhotoId: Int64, author: String, date: Int32, blocks: [Api.PageBlock], caption: Api.PageCaption) + case pageBlockCollage(items: [Api.PageBlock], caption: Api.PageCaption) + case pageBlockSlideshow(items: [Api.PageBlock], caption: Api.PageCaption) + case pageBlockList(items: [Api.PageListItem]) + case pageBlockOrderedList(items: [Api.PageListOrderedItem]) + case pageBlockDetails(flags: Int32, blocks: [Api.PageBlock], title: Api.RichText) + case pageBlockRelatedArticles(title: Api.RichText, articles: [Api.PageRelatedArticle]) + case pageBlockMap(geo: Api.GeoPoint, zoom: Int32, w: Int32, h: Int32, caption: Api.PageCaption) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageBlockUnsupported: + if boxed { + buffer.appendInt32(324435594) + } + + break + case .pageBlockTitle(let text): + if boxed { + buffer.appendInt32(1890305021) + } + text.serialize(buffer, true) + break + case .pageBlockSubtitle(let text): + if boxed { + buffer.appendInt32(-1879401953) + } + text.serialize(buffer, true) + break + case .pageBlockAuthorDate(let author, let publishedDate): + if boxed { + buffer.appendInt32(-1162877472) + } + author.serialize(buffer, true) + serializeInt32(publishedDate, buffer: buffer, boxed: false) + break + case .pageBlockHeader(let text): + if boxed { + buffer.appendInt32(-1076861716) + } + text.serialize(buffer, true) + break + case .pageBlockSubheader(let text): + if boxed { + buffer.appendInt32(-248793375) + } + text.serialize(buffer, true) + break + case .pageBlockParagraph(let text): + if boxed { + buffer.appendInt32(1182402406) + } + text.serialize(buffer, true) + break + case .pageBlockPreformatted(let text, let language): + if boxed { + buffer.appendInt32(-1066346178) + } + text.serialize(buffer, true) + serializeString(language, buffer: buffer, boxed: false) + break + case .pageBlockFooter(let text): + if boxed { + buffer.appendInt32(1216809369) + } + text.serialize(buffer, true) + break + case .pageBlockDivider: + if boxed { + buffer.appendInt32(-618614392) + } + + break + case .pageBlockAnchor(let name): + if boxed { + buffer.appendInt32(-837994576) + } + serializeString(name, buffer: buffer, boxed: false) + break + case .pageBlockBlockquote(let text, let caption): + if boxed { + buffer.appendInt32(641563686) + } + text.serialize(buffer, true) + caption.serialize(buffer, true) + break + case .pageBlockPullquote(let text, let caption): + if boxed { + buffer.appendInt32(1329878739) + } + text.serialize(buffer, true) + caption.serialize(buffer, true) + break + case .pageBlockCover(let cover): + if boxed { + buffer.appendInt32(972174080) + } + cover.serialize(buffer, true) + break + case .pageBlockChannel(let channel): + if boxed { + buffer.appendInt32(-283684427) + } + channel.serialize(buffer, true) + break + case .pageBlockKicker(let text): + if boxed { + buffer.appendInt32(504660880) + } + text.serialize(buffer, true) + break + case .pageBlockTable(let flags, let title, let rows): + if boxed { + buffer.appendInt32(-1085412734) + } + serializeInt32(flags, buffer: buffer, boxed: false) + title.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rows.count)) + for item in rows { + item.serialize(buffer, true) + } + break + case .pageBlockPhoto(let flags, let photoId, let caption, let url, let webpageId): + if boxed { + buffer.appendInt32(391759200) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(photoId, buffer: buffer, boxed: false) + caption.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 0) != 0 {serializeInt64(webpageId!, buffer: buffer, boxed: false)} + break + case .pageBlockVideo(let flags, let videoId, let caption): + if boxed { + buffer.appendInt32(2089805750) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(videoId, buffer: buffer, boxed: false) + caption.serialize(buffer, true) + break + case .pageBlockAudio(let audioId, let caption): + if boxed { + buffer.appendInt32(-2143067670) + } + serializeInt64(audioId, buffer: buffer, boxed: false) + caption.serialize(buffer, true) + break + case .pageBlockEmbed(let flags, let url, let html, let posterPhotoId, let w, let h, let caption): + if boxed { + buffer.appendInt32(-1468953147) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(html!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt64(posterPhotoId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeInt32(w!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeInt32(h!, buffer: buffer, boxed: false)} + caption.serialize(buffer, true) + break + case .pageBlockEmbedPost(let url, let webpageId, let authorPhotoId, let author, let date, let blocks, let caption): + if boxed { + buffer.appendInt32(-229005301) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(webpageId, buffer: buffer, boxed: false) + serializeInt64(authorPhotoId, buffer: buffer, boxed: false) + serializeString(author, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + caption.serialize(buffer, true) + break + case .pageBlockCollage(let items, let caption): + if boxed { + buffer.appendInt32(1705048653) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(items.count)) + for item in items { + item.serialize(buffer, true) + } + caption.serialize(buffer, true) + break + case .pageBlockSlideshow(let items, let caption): + if boxed { + buffer.appendInt32(52401552) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(items.count)) + for item in items { + item.serialize(buffer, true) + } + caption.serialize(buffer, true) + break + case .pageBlockList(let items): + if boxed { + buffer.appendInt32(-454524911) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(items.count)) + for item in items { + item.serialize(buffer, true) + } + break + case .pageBlockOrderedList(let items): + if boxed { + buffer.appendInt32(-1702174239) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(items.count)) + for item in items { + item.serialize(buffer, true) + } + break + case .pageBlockDetails(let flags, let blocks, let title): + if boxed { + buffer.appendInt32(1987480557) + } + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + title.serialize(buffer, true) + break + case .pageBlockRelatedArticles(let title, let articles): + if boxed { + buffer.appendInt32(370236054) + } + title.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(articles.count)) + for item in articles { + item.serialize(buffer, true) + } + break + case .pageBlockMap(let geo, let zoom, let w, let h, let caption): + if boxed { + buffer.appendInt32(-1538310410) + } + geo.serialize(buffer, true) + serializeInt32(zoom, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + caption.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageBlockUnsupported: + return ("pageBlockUnsupported", []) + case .pageBlockTitle(let text): + return ("pageBlockTitle", [("text", text)]) + case .pageBlockSubtitle(let text): + return ("pageBlockSubtitle", [("text", text)]) + case .pageBlockAuthorDate(let author, let publishedDate): + return ("pageBlockAuthorDate", [("author", author), ("publishedDate", publishedDate)]) + case .pageBlockHeader(let text): + return ("pageBlockHeader", [("text", text)]) + case .pageBlockSubheader(let text): + return ("pageBlockSubheader", [("text", text)]) + case .pageBlockParagraph(let text): + return ("pageBlockParagraph", [("text", text)]) + case .pageBlockPreformatted(let text, let language): + return ("pageBlockPreformatted", [("text", text), ("language", language)]) + case .pageBlockFooter(let text): + return ("pageBlockFooter", [("text", text)]) + case .pageBlockDivider: + return ("pageBlockDivider", []) + case .pageBlockAnchor(let name): + return ("pageBlockAnchor", [("name", name)]) + case .pageBlockBlockquote(let text, let caption): + return ("pageBlockBlockquote", [("text", text), ("caption", caption)]) + case .pageBlockPullquote(let text, let caption): + return ("pageBlockPullquote", [("text", text), ("caption", caption)]) + case .pageBlockCover(let cover): + return ("pageBlockCover", [("cover", cover)]) + case .pageBlockChannel(let channel): + return ("pageBlockChannel", [("channel", channel)]) + case .pageBlockKicker(let text): + return ("pageBlockKicker", [("text", text)]) + case .pageBlockTable(let flags, let title, let rows): + return ("pageBlockTable", [("flags", flags), ("title", title), ("rows", rows)]) + case .pageBlockPhoto(let flags, let photoId, let caption, let url, let webpageId): + return ("pageBlockPhoto", [("flags", flags), ("photoId", photoId), ("caption", caption), ("url", url), ("webpageId", webpageId)]) + case .pageBlockVideo(let flags, let videoId, let caption): + return ("pageBlockVideo", [("flags", flags), ("videoId", videoId), ("caption", caption)]) + case .pageBlockAudio(let audioId, let caption): + return ("pageBlockAudio", [("audioId", audioId), ("caption", caption)]) + case .pageBlockEmbed(let flags, let url, let html, let posterPhotoId, let w, let h, let caption): + return ("pageBlockEmbed", [("flags", flags), ("url", url), ("html", html), ("posterPhotoId", posterPhotoId), ("w", w), ("h", h), ("caption", caption)]) + case .pageBlockEmbedPost(let url, let webpageId, let authorPhotoId, let author, let date, let blocks, let caption): + return ("pageBlockEmbedPost", [("url", url), ("webpageId", webpageId), ("authorPhotoId", authorPhotoId), ("author", author), ("date", date), ("blocks", blocks), ("caption", caption)]) + case .pageBlockCollage(let items, let caption): + return ("pageBlockCollage", [("items", items), ("caption", caption)]) + case .pageBlockSlideshow(let items, let caption): + return ("pageBlockSlideshow", [("items", items), ("caption", caption)]) + case .pageBlockList(let items): + return ("pageBlockList", [("items", items)]) + case .pageBlockOrderedList(let items): + return ("pageBlockOrderedList", [("items", items)]) + case .pageBlockDetails(let flags, let blocks, let title): + return ("pageBlockDetails", [("flags", flags), ("blocks", blocks), ("title", title)]) + case .pageBlockRelatedArticles(let title, let articles): + return ("pageBlockRelatedArticles", [("title", title), ("articles", articles)]) + case .pageBlockMap(let geo, let zoom, let w, let h, let caption): + return ("pageBlockMap", [("geo", geo), ("zoom", zoom), ("w", w), ("h", h), ("caption", caption)]) + } + } + + static func parse_pageBlockUnsupported(_ reader: BufferReader) -> PageBlock? { + return Api.PageBlock.pageBlockUnsupported + } + static func parse_pageBlockTitle(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockTitle(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockSubtitle(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockSubtitle(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockAuthorDate(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockAuthorDate(author: _1!, publishedDate: _2!) + } + else { + return nil + } + } + static func parse_pageBlockHeader(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockHeader(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockSubheader(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockSubheader(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockParagraph(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockParagraph(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockPreformatted(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockPreformatted(text: _1!, language: _2!) + } + else { + return nil + } + } + static func parse_pageBlockFooter(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockFooter(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockDivider(_ reader: BufferReader) -> PageBlock? { + return Api.PageBlock.pageBlockDivider + } + static func parse_pageBlockAnchor(_ reader: BufferReader) -> PageBlock? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockAnchor(name: _1!) + } + else { + return nil + } + } + static func parse_pageBlockBlockquote(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: Api.RichText? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockBlockquote(text: _1!, caption: _2!) + } + else { + return nil + } + } + static func parse_pageBlockPullquote(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: Api.RichText? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockPullquote(text: _1!, caption: _2!) + } + else { + return nil + } + } + static func parse_pageBlockCover(_ reader: BufferReader) -> PageBlock? { + var _1: Api.PageBlock? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.PageBlock + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockCover(cover: _1!) + } + else { + return nil + } + } + static func parse_pageBlockChannel(_ reader: BufferReader) -> PageBlock? { + var _1: Api.Chat? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Chat + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockChannel(channel: _1!) + } + else { + return nil + } + } + static func parse_pageBlockKicker(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockKicker(text: _1!) + } + else { + return nil + } + } + static func parse_pageBlockTable(_ reader: BufferReader) -> PageBlock? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.RichText? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _3: [Api.PageTableRow]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageTableRow.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.PageBlock.pageBlockTable(flags: _1!, title: _2!, rows: _3!) + } + else { + return nil + } + } + static func parse_pageBlockPhoto(_ reader: BufferReader) -> PageBlock? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.PageCaption? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + var _4: String? + if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + var _5: Int64? + if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt64() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PageBlock.pageBlockPhoto(flags: _1!, photoId: _2!, caption: _3!, url: _4, webpageId: _5) + } + else { + return nil + } + } + static func parse_pageBlockVideo(_ reader: BufferReader) -> PageBlock? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.PageCaption? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.PageBlock.pageBlockVideo(flags: _1!, videoId: _2!, caption: _3!) + } + else { + return nil + } + } + static func parse_pageBlockAudio(_ reader: BufferReader) -> PageBlock? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Api.PageCaption? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockAudio(audioId: _1!, caption: _2!) + } + else { + return nil + } + } + static func parse_pageBlockEmbed(_ reader: BufferReader) -> PageBlock? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 1) != 0 {_2 = parseString(reader) } + var _3: String? + if Int(_1!) & Int(1 << 2) != 0 {_3 = parseString(reader) } + var _4: Int64? + if Int(_1!) & Int(1 << 4) != 0 {_4 = reader.readInt64() } + var _5: Int32? + if Int(_1!) & Int(1 << 5) != 0 {_5 = reader.readInt32() } + var _6: Int32? + if Int(_1!) & Int(1 << 5) != 0 {_6 = reader.readInt32() } + var _7: Api.PageCaption? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 5) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 5) == 0) || _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.PageBlock.pageBlockEmbed(flags: _1!, url: _2, html: _3, posterPhotoId: _4, w: _5, h: _6, caption: _7!) + } + else { + return nil + } + } + static func parse_pageBlockEmbedPost(_ reader: BufferReader) -> PageBlock? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: [Api.PageBlock]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _7: Api.PageCaption? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.PageBlock.pageBlockEmbedPost(url: _1!, webpageId: _2!, authorPhotoId: _3!, author: _4!, date: _5!, blocks: _6!, caption: _7!) + } + else { + return nil + } + } + static func parse_pageBlockCollage(_ reader: BufferReader) -> PageBlock? { + var _1: [Api.PageBlock]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _2: Api.PageCaption? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockCollage(items: _1!, caption: _2!) + } + else { + return nil + } + } + static func parse_pageBlockSlideshow(_ reader: BufferReader) -> PageBlock? { + var _1: [Api.PageBlock]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _2: Api.PageCaption? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockSlideshow(items: _1!, caption: _2!) + } + else { + return nil + } + } + static func parse_pageBlockList(_ reader: BufferReader) -> PageBlock? { + var _1: [Api.PageListItem]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageListItem.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockList(items: _1!) + } + else { + return nil + } + } + static func parse_pageBlockOrderedList(_ reader: BufferReader) -> PageBlock? { + var _1: [Api.PageListOrderedItem]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageListOrderedItem.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PageBlock.pageBlockOrderedList(items: _1!) + } + else { + return nil + } + } + static func parse_pageBlockDetails(_ reader: BufferReader) -> PageBlock? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.PageBlock]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _3: Api.RichText? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.PageBlock.pageBlockDetails(flags: _1!, blocks: _2!, title: _3!) + } + else { + return nil + } + } + static func parse_pageBlockRelatedArticles(_ reader: BufferReader) -> PageBlock? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: [Api.PageRelatedArticle]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageRelatedArticle.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageBlock.pageBlockRelatedArticles(title: _1!, articles: _2!) + } + else { + return nil + } + } + static func parse_pageBlockMap(_ reader: BufferReader) -> PageBlock? { + var _1: Api.GeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Api.PageCaption? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.PageCaption + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PageBlock.pageBlockMap(geo: _1!, zoom: _2!, w: _3!, h: _4!, caption: _5!) + } + else { + return nil + } + } + + } + enum SecureRequiredType: TypeConstructorDescription { + case secureRequiredType(flags: Int32, type: Api.SecureValueType) + case secureRequiredTypeOneOf(types: [Api.SecureRequiredType]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureRequiredType(let flags, let type): + if boxed { + buffer.appendInt32(-2103600678) + } + serializeInt32(flags, buffer: buffer, boxed: false) + type.serialize(buffer, true) + break + case .secureRequiredTypeOneOf(let types): + if boxed { + buffer.appendInt32(41187252) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureRequiredType(let flags, let type): + return ("secureRequiredType", [("flags", flags), ("type", type)]) + case .secureRequiredTypeOneOf(let types): + return ("secureRequiredTypeOneOf", [("types", types)]) + } + } + + static func parse_secureRequiredType(_ reader: BufferReader) -> SecureRequiredType? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureValueType? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.SecureRequiredType.secureRequiredType(flags: _1!, type: _2!) + } + else { + return nil + } + } + static func parse_secureRequiredTypeOneOf(_ reader: BufferReader) -> SecureRequiredType? { + var _1: [Api.SecureRequiredType]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureRequiredType.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.SecureRequiredType.secureRequiredTypeOneOf(types: _1!) + } + else { + return nil + } + } + + } + enum JSONValue: TypeConstructorDescription { + case jsonNull + case jsonBool(value: Api.Bool) + case jsonNumber(value: Double) + case jsonString(value: String) + case jsonArray(value: [Api.JSONValue]) + case jsonObject(value: [Api.JSONObjectValue]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .jsonNull: + if boxed { + buffer.appendInt32(1064139624) + } + + break + case .jsonBool(let value): + if boxed { + buffer.appendInt32(-952869270) + } + value.serialize(buffer, true) + break + case .jsonNumber(let value): + if boxed { + buffer.appendInt32(736157604) + } + serializeDouble(value, buffer: buffer, boxed: false) + break + case .jsonString(let value): + if boxed { + buffer.appendInt32(-1222740358) + } + serializeString(value, buffer: buffer, boxed: false) + break + case .jsonArray(let value): + if boxed { + buffer.appendInt32(-146520221) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(value.count)) + for item in value { + item.serialize(buffer, true) + } + break + case .jsonObject(let value): + if boxed { + buffer.appendInt32(-1715350371) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(value.count)) + for item in value { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .jsonNull: + return ("jsonNull", []) + case .jsonBool(let value): + return ("jsonBool", [("value", value)]) + case .jsonNumber(let value): + return ("jsonNumber", [("value", value)]) + case .jsonString(let value): + return ("jsonString", [("value", value)]) + case .jsonArray(let value): + return ("jsonArray", [("value", value)]) + case .jsonObject(let value): + return ("jsonObject", [("value", value)]) + } + } + + static func parse_jsonNull(_ reader: BufferReader) -> JSONValue? { + return Api.JSONValue.jsonNull + } + static func parse_jsonBool(_ reader: BufferReader) -> JSONValue? { + var _1: Api.Bool? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + if _c1 { + return Api.JSONValue.jsonBool(value: _1!) + } + else { + return nil + } + } + static func parse_jsonNumber(_ reader: BufferReader) -> JSONValue? { + var _1: Double? + _1 = reader.readDouble() + let _c1 = _1 != nil + if _c1 { + return Api.JSONValue.jsonNumber(value: _1!) + } + else { + return nil + } + } + static func parse_jsonString(_ reader: BufferReader) -> JSONValue? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.JSONValue.jsonString(value: _1!) + } + else { + return nil + } + } + static func parse_jsonArray(_ reader: BufferReader) -> JSONValue? { + var _1: [Api.JSONValue]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.JSONValue.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.JSONValue.jsonArray(value: _1!) + } + else { + return nil + } + } + static func parse_jsonObject(_ reader: BufferReader) -> JSONValue? { + var _1: [Api.JSONObjectValue]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.JSONObjectValue.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.JSONValue.jsonObject(value: _1!) + } + else { + return nil + } + } + + } + enum Photo: TypeConstructorDescription { + case photoEmpty(id: Int64) + case photo(flags: Int32, id: Int64, accessHash: Int64, fileReference: Buffer, date: Int32, sizes: [Api.PhotoSize], dcId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photoEmpty(let id): + if boxed { + buffer.appendInt32(590459437) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + case .photo(let flags, let id, let accessHash, let fileReference, let date, let sizes, let dcId): + if boxed { + buffer.appendInt32(-797637467) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sizes.count)) + for item in sizes { + item.serialize(buffer, true) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .photoEmpty(let id): + return ("photoEmpty", [("id", id)]) + case .photo(let flags, let id, let accessHash, let fileReference, let date, let sizes, let dcId): + return ("photo", [("flags", flags), ("id", id), ("accessHash", accessHash), ("fileReference", fileReference), ("date", date), ("sizes", sizes), ("dcId", dcId)]) + } + } + + static func parse_photoEmpty(_ reader: BufferReader) -> Photo? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.Photo.photoEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_photo(_ reader: BufferReader) -> Photo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: [Api.PhotoSize]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhotoSize.self) + } + var _7: Int32? + _7 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.Photo.photo(flags: _1!, id: _2!, accessHash: _3!, fileReference: _4!, date: _5!, sizes: _6!, dcId: _7!) + } + else { + return nil + } + } + + } + enum Chat: TypeConstructorDescription { + case chatEmpty(id: Int32) + case chatForbidden(id: Int32, title: String) + case channelForbidden(flags: Int32, id: Int32, accessHash: Int64, title: String, untilDate: Int32?) + case chat(flags: Int32, id: Int32, title: String, photo: Api.ChatPhoto, participantsCount: Int32, date: Int32, version: Int32, migratedTo: Api.InputChannel?, adminRights: Api.ChatAdminRights?, defaultBannedRights: Api.ChatBannedRights?) + case channel(flags: Int32, id: Int32, accessHash: Int64?, title: String, username: String?, photo: Api.ChatPhoto, date: Int32, version: Int32, restrictionReason: String?, adminRights: Api.ChatAdminRights?, bannedRights: Api.ChatBannedRights?, defaultBannedRights: Api.ChatBannedRights?, participantsCount: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatEmpty(let id): + if boxed { + buffer.appendInt32(-1683826688) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .chatForbidden(let id, let title): + if boxed { + buffer.appendInt32(120753115) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + break + case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate): + if boxed { + buffer.appendInt32(681420594) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 16) != 0 {serializeInt32(untilDate!, buffer: buffer, boxed: false)} + break + case .chat(let flags, let id, let title, let photo, let participantsCount, let date, let version, let migratedTo, let adminRights, let defaultBannedRights): + if boxed { + buffer.appendInt32(1004149726) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + serializeInt32(participantsCount, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 6) != 0 {migratedTo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 14) != 0 {adminRights!.serialize(buffer, true)} + if Int(flags) & Int(1 << 18) != 0 {defaultBannedRights!.serialize(buffer, true)} + break + case .channel(let flags, let id, let accessHash, let title, let username, let photo, let date, let version, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount): + if boxed { + buffer.appendInt32(1307772980) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 13) != 0 {serializeInt64(accessHash!, buffer: buffer, boxed: false)} + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 6) != 0 {serializeString(username!, buffer: buffer, boxed: false)} + photo.serialize(buffer, true) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 9) != 0 {serializeString(restrictionReason!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 14) != 0 {adminRights!.serialize(buffer, true)} + if Int(flags) & Int(1 << 15) != 0 {bannedRights!.serialize(buffer, true)} + if Int(flags) & Int(1 << 18) != 0 {defaultBannedRights!.serialize(buffer, true)} + if Int(flags) & Int(1 << 17) != 0 {serializeInt32(participantsCount!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatEmpty(let id): + return ("chatEmpty", [("id", id)]) + case .chatForbidden(let id, let title): + return ("chatForbidden", [("id", id), ("title", title)]) + case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate): + return ("channelForbidden", [("flags", flags), ("id", id), ("accessHash", accessHash), ("title", title), ("untilDate", untilDate)]) + case .chat(let flags, let id, let title, let photo, let participantsCount, let date, let version, let migratedTo, let adminRights, let defaultBannedRights): + return ("chat", [("flags", flags), ("id", id), ("title", title), ("photo", photo), ("participantsCount", participantsCount), ("date", date), ("version", version), ("migratedTo", migratedTo), ("adminRights", adminRights), ("defaultBannedRights", defaultBannedRights)]) + case .channel(let flags, let id, let accessHash, let title, let username, let photo, let date, let version, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount): + return ("channel", [("flags", flags), ("id", id), ("accessHash", accessHash), ("title", title), ("username", username), ("photo", photo), ("date", date), ("version", version), ("restrictionReason", restrictionReason), ("adminRights", adminRights), ("bannedRights", bannedRights), ("defaultBannedRights", defaultBannedRights), ("participantsCount", participantsCount)]) + } + } + + static func parse_chatEmpty(_ reader: BufferReader) -> Chat? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Chat.chatEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_chatForbidden(_ reader: BufferReader) -> Chat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Chat.chatForbidden(id: _1!, title: _2!) + } + else { + return nil + } + } + static func parse_channelForbidden(_ reader: BufferReader) -> Chat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + if Int(_1!) & Int(1 << 16) != 0 {_5 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 16) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.Chat.channelForbidden(flags: _1!, id: _2!, accessHash: _3!, title: _4!, untilDate: _5) + } + else { + return nil + } + } + static func parse_chat(_ reader: BufferReader) -> Chat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Api.ChatPhoto? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ChatPhoto + } + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Api.InputChannel? + if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.InputChannel + } } + var _9: Api.ChatAdminRights? + if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights + } } + var _10: Api.ChatBannedRights? + if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 6) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 14) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 18) == 0) || _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.Chat.chat(flags: _1!, id: _2!, title: _3!, photo: _4!, participantsCount: _5!, date: _6!, version: _7!, migratedTo: _8, adminRights: _9, defaultBannedRights: _10) + } + else { + return nil + } + } + static func parse_channel(_ reader: BufferReader) -> Chat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + if Int(_1!) & Int(1 << 13) != 0 {_3 = reader.readInt64() } + var _4: String? + _4 = parseString(reader) + var _5: String? + if Int(_1!) & Int(1 << 6) != 0 {_5 = parseString(reader) } + var _6: Api.ChatPhoto? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.ChatPhoto + } + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + var _9: String? + if Int(_1!) & Int(1 << 9) != 0 {_9 = parseString(reader) } + var _10: Api.ChatAdminRights? + if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights + } } + var _11: Api.ChatBannedRights? + if Int(_1!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } } + var _12: Api.ChatBannedRights? + if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } } + var _13: Int32? + if Int(_1!) & Int(1 << 17) != 0 {_13 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 13) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 6) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = (Int(_1!) & Int(1 << 9) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 14) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 15) == 0) || _11 != nil + let _c12 = (Int(_1!) & Int(1 << 18) == 0) || _12 != nil + let _c13 = (Int(_1!) & Int(1 << 17) == 0) || _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.Chat.channel(flags: _1!, id: _2!, accessHash: _3, title: _4!, username: _5, photo: _6!, date: _7!, version: _8!, restrictionReason: _9, adminRights: _10, bannedRights: _11, defaultBannedRights: _12, participantsCount: _13) + } + else { + return nil + } + } + + } + enum StatsURL: TypeConstructorDescription { + case statsURL(url: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsURL(let url): + if boxed { + buffer.appendInt32(1202287072) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsURL(let url): + return ("statsURL", [("url", url)]) + } + } + + static func parse_statsURL(_ reader: BufferReader) -> StatsURL? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsURL.statsURL(url: _1!) + } + else { + return nil + } + } + + } + enum ChatInvite: TypeConstructorDescription { + case chatInviteAlready(chat: Api.Chat) + case chatInvite(flags: Int32, title: String, photo: Api.Photo, participantsCount: Int32, participants: [Api.User]?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatInviteAlready(let chat): + if boxed { + buffer.appendInt32(1516793212) + } + chat.serialize(buffer, true) + break + case .chatInvite(let flags, let title, let photo, let participantsCount, let participants): + if boxed { + buffer.appendInt32(-540871282) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + serializeInt32(participantsCount, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(participants!.count)) + for item in participants! { + item.serialize(buffer, true) + }} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatInviteAlready(let chat): + return ("chatInviteAlready", [("chat", chat)]) + case .chatInvite(let flags, let title, let photo, let participantsCount, let participants): + return ("chatInvite", [("flags", flags), ("title", title), ("photo", photo), ("participantsCount", participantsCount), ("participants", participants)]) + } + } + + static func parse_chatInviteAlready(_ reader: BufferReader) -> ChatInvite? { + var _1: Api.Chat? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Chat + } + let _c1 = _1 != nil + if _c1 { + return Api.ChatInvite.chatInviteAlready(chat: _1!) + } + else { + return nil + } + } + static func parse_chatInvite(_ reader: BufferReader) -> ChatInvite? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Api.Photo? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _4: Int32? + _4 = reader.readInt32() + var _5: [Api.User]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.ChatInvite.chatInvite(flags: _1!, title: _2!, photo: _3!, participantsCount: _4!, participants: _5) + } + else { + return nil + } + } + + } + enum AutoDownloadSettings: TypeConstructorDescription { + case autoDownloadSettings(flags: Int32, photoSizeMax: Int32, videoSizeMax: Int32, fileSizeMax: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .autoDownloadSettings(let flags, let photoSizeMax, let videoSizeMax, let fileSizeMax): + if boxed { + buffer.appendInt32(-767099577) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(photoSizeMax, buffer: buffer, boxed: false) + serializeInt32(videoSizeMax, buffer: buffer, boxed: false) + serializeInt32(fileSizeMax, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .autoDownloadSettings(let flags, let photoSizeMax, let videoSizeMax, let fileSizeMax): + return ("autoDownloadSettings", [("flags", flags), ("photoSizeMax", photoSizeMax), ("videoSizeMax", videoSizeMax), ("fileSizeMax", fileSizeMax)]) + } + } + + static func parse_autoDownloadSettings(_ reader: BufferReader) -> AutoDownloadSettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.AutoDownloadSettings.autoDownloadSettings(flags: _1!, photoSizeMax: _2!, videoSizeMax: _3!, fileSizeMax: _4!) + } + else { + return nil + } + } + + } + enum StickerSetCovered: TypeConstructorDescription { + case stickerSetCovered(set: Api.StickerSet, cover: Api.Document) + case stickerSetMultiCovered(set: Api.StickerSet, covers: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickerSetCovered(let set, let cover): + if boxed { + buffer.appendInt32(1678812626) + } + set.serialize(buffer, true) + cover.serialize(buffer, true) + break + case .stickerSetMultiCovered(let set, let covers): + if boxed { + buffer.appendInt32(872932635) + } + set.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(covers.count)) + for item in covers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickerSetCovered(let set, let cover): + return ("stickerSetCovered", [("set", set), ("cover", cover)]) + case .stickerSetMultiCovered(let set, let covers): + return ("stickerSetMultiCovered", [("set", set), ("covers", covers)]) + } + } + + static func parse_stickerSetCovered(_ reader: BufferReader) -> StickerSetCovered? { + var _1: Api.StickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StickerSet + } + var _2: Api.Document? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Document + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StickerSetCovered.stickerSetCovered(set: _1!, cover: _2!) + } + else { + return nil + } + } + static func parse_stickerSetMultiCovered(_ reader: BufferReader) -> StickerSetCovered? { + var _1: Api.StickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StickerSet + } + var _2: [Api.Document]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StickerSetCovered.stickerSetMultiCovered(set: _1!, covers: _2!) + } + else { + return nil + } + } + + } + enum RecentMeUrl: TypeConstructorDescription { + case recentMeUrlUnknown(url: String) + case recentMeUrlUser(url: String, userId: Int32) + case recentMeUrlChat(url: String, chatId: Int32) + case recentMeUrlChatInvite(url: String, chatInvite: Api.ChatInvite) + case recentMeUrlStickerSet(url: String, set: Api.StickerSetCovered) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .recentMeUrlUnknown(let url): + if boxed { + buffer.appendInt32(1189204285) + } + serializeString(url, buffer: buffer, boxed: false) + break + case .recentMeUrlUser(let url, let userId): + if boxed { + buffer.appendInt32(-1917045962) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .recentMeUrlChat(let url, let chatId): + if boxed { + buffer.appendInt32(-1608834311) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + break + case .recentMeUrlChatInvite(let url, let chatInvite): + if boxed { + buffer.appendInt32(-347535331) + } + serializeString(url, buffer: buffer, boxed: false) + chatInvite.serialize(buffer, true) + break + case .recentMeUrlStickerSet(let url, let set): + if boxed { + buffer.appendInt32(-1140172836) + } + serializeString(url, buffer: buffer, boxed: false) + set.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .recentMeUrlUnknown(let url): + return ("recentMeUrlUnknown", [("url", url)]) + case .recentMeUrlUser(let url, let userId): + return ("recentMeUrlUser", [("url", url), ("userId", userId)]) + case .recentMeUrlChat(let url, let chatId): + return ("recentMeUrlChat", [("url", url), ("chatId", chatId)]) + case .recentMeUrlChatInvite(let url, let chatInvite): + return ("recentMeUrlChatInvite", [("url", url), ("chatInvite", chatInvite)]) + case .recentMeUrlStickerSet(let url, let set): + return ("recentMeUrlStickerSet", [("url", url), ("set", set)]) + } + } + + static func parse_recentMeUrlUnknown(_ reader: BufferReader) -> RecentMeUrl? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.RecentMeUrl.recentMeUrlUnknown(url: _1!) + } + else { + return nil + } + } + static func parse_recentMeUrlUser(_ reader: BufferReader) -> RecentMeUrl? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RecentMeUrl.recentMeUrlUser(url: _1!, userId: _2!) + } + else { + return nil + } + } + static func parse_recentMeUrlChat(_ reader: BufferReader) -> RecentMeUrl? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RecentMeUrl.recentMeUrlChat(url: _1!, chatId: _2!) + } + else { + return nil + } + } + static func parse_recentMeUrlChatInvite(_ reader: BufferReader) -> RecentMeUrl? { + var _1: String? + _1 = parseString(reader) + var _2: Api.ChatInvite? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ChatInvite + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RecentMeUrl.recentMeUrlChatInvite(url: _1!, chatInvite: _2!) + } + else { + return nil + } + } + static func parse_recentMeUrlStickerSet(_ reader: BufferReader) -> RecentMeUrl? { + var _1: String? + _1 = parseString(reader) + var _2: Api.StickerSetCovered? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StickerSetCovered + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RecentMeUrl.recentMeUrlStickerSet(url: _1!, set: _2!) + } + else { + return nil + } + } + + } + indirect enum RichText: TypeConstructorDescription { + case textEmpty + case textPlain(text: String) + case textBold(text: Api.RichText) + case textItalic(text: Api.RichText) + case textUnderline(text: Api.RichText) + case textStrike(text: Api.RichText) + case textFixed(text: Api.RichText) + case textUrl(text: Api.RichText, url: String, webpageId: Int64) + case textEmail(text: Api.RichText, email: String) + case textConcat(texts: [Api.RichText]) + case textSubscript(text: Api.RichText) + case textSuperscript(text: Api.RichText) + case textMarked(text: Api.RichText) + case textPhone(text: Api.RichText, phone: String) + case textImage(documentId: Int64, w: Int32, h: Int32) + case textAnchor(text: Api.RichText, name: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .textEmpty: + if boxed { + buffer.appendInt32(-599948721) + } + + break + case .textPlain(let text): + if boxed { + buffer.appendInt32(1950782688) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .textBold(let text): + if boxed { + buffer.appendInt32(1730456516) + } + text.serialize(buffer, true) + break + case .textItalic(let text): + if boxed { + buffer.appendInt32(-653089380) + } + text.serialize(buffer, true) + break + case .textUnderline(let text): + if boxed { + buffer.appendInt32(-1054465340) + } + text.serialize(buffer, true) + break + case .textStrike(let text): + if boxed { + buffer.appendInt32(-1678197867) + } + text.serialize(buffer, true) + break + case .textFixed(let text): + if boxed { + buffer.appendInt32(1816074681) + } + text.serialize(buffer, true) + break + case .textUrl(let text, let url, let webpageId): + if boxed { + buffer.appendInt32(1009288385) + } + text.serialize(buffer, true) + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(webpageId, buffer: buffer, boxed: false) + break + case .textEmail(let text, let email): + if boxed { + buffer.appendInt32(-564523562) + } + text.serialize(buffer, true) + serializeString(email, buffer: buffer, boxed: false) + break + case .textConcat(let texts): + if boxed { + buffer.appendInt32(2120376535) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(texts.count)) + for item in texts { + item.serialize(buffer, true) + } + break + case .textSubscript(let text): + if boxed { + buffer.appendInt32(-311786236) + } + text.serialize(buffer, true) + break + case .textSuperscript(let text): + if boxed { + buffer.appendInt32(-939827711) + } + text.serialize(buffer, true) + break + case .textMarked(let text): + if boxed { + buffer.appendInt32(55281185) + } + text.serialize(buffer, true) + break + case .textPhone(let text, let phone): + if boxed { + buffer.appendInt32(483104362) + } + text.serialize(buffer, true) + serializeString(phone, buffer: buffer, boxed: false) + break + case .textImage(let documentId, let w, let h): + if boxed { + buffer.appendInt32(136105807) + } + serializeInt64(documentId, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .textAnchor(let text, let name): + if boxed { + buffer.appendInt32(894777186) + } + text.serialize(buffer, true) + serializeString(name, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .textEmpty: + return ("textEmpty", []) + case .textPlain(let text): + return ("textPlain", [("text", text)]) + case .textBold(let text): + return ("textBold", [("text", text)]) + case .textItalic(let text): + return ("textItalic", [("text", text)]) + case .textUnderline(let text): + return ("textUnderline", [("text", text)]) + case .textStrike(let text): + return ("textStrike", [("text", text)]) + case .textFixed(let text): + return ("textFixed", [("text", text)]) + case .textUrl(let text, let url, let webpageId): + return ("textUrl", [("text", text), ("url", url), ("webpageId", webpageId)]) + case .textEmail(let text, let email): + return ("textEmail", [("text", text), ("email", email)]) + case .textConcat(let texts): + return ("textConcat", [("texts", texts)]) + case .textSubscript(let text): + return ("textSubscript", [("text", text)]) + case .textSuperscript(let text): + return ("textSuperscript", [("text", text)]) + case .textMarked(let text): + return ("textMarked", [("text", text)]) + case .textPhone(let text, let phone): + return ("textPhone", [("text", text), ("phone", phone)]) + case .textImage(let documentId, let w, let h): + return ("textImage", [("documentId", documentId), ("w", w), ("h", h)]) + case .textAnchor(let text, let name): + return ("textAnchor", [("text", text), ("name", name)]) + } + } + + static func parse_textEmpty(_ reader: BufferReader) -> RichText? { + return Api.RichText.textEmpty + } + static func parse_textPlain(_ reader: BufferReader) -> RichText? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textPlain(text: _1!) + } + else { + return nil + } + } + static func parse_textBold(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textBold(text: _1!) + } + else { + return nil + } + } + static func parse_textItalic(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textItalic(text: _1!) + } + else { + return nil + } + } + static func parse_textUnderline(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textUnderline(text: _1!) + } + else { + return nil + } + } + static func parse_textStrike(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textStrike(text: _1!) + } + else { + return nil + } + } + static func parse_textFixed(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textFixed(text: _1!) + } + else { + return nil + } + } + static func parse_textUrl(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: String? + _2 = parseString(reader) + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.RichText.textUrl(text: _1!, url: _2!, webpageId: _3!) + } + else { + return nil + } + } + static func parse_textEmail(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RichText.textEmail(text: _1!, email: _2!) + } + else { + return nil + } + } + static func parse_textConcat(_ reader: BufferReader) -> RichText? { + var _1: [Api.RichText]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RichText.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textConcat(texts: _1!) + } + else { + return nil + } + } + static func parse_textSubscript(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textSubscript(text: _1!) + } + else { + return nil + } + } + static func parse_textSuperscript(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textSuperscript(text: _1!) + } + else { + return nil + } + } + static func parse_textMarked(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.RichText.textMarked(text: _1!) + } + else { + return nil + } + } + static func parse_textPhone(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RichText.textPhone(text: _1!, phone: _2!) + } + else { + return nil + } + } + static func parse_textImage(_ reader: BufferReader) -> RichText? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.RichText.textImage(documentId: _1!, w: _2!, h: _3!) + } + else { + return nil + } + } + static func parse_textAnchor(_ reader: BufferReader) -> RichText? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.RichText.textAnchor(text: _1!, name: _2!) + } + else { + return nil + } + } + + } + enum UserFull: TypeConstructorDescription { + case userFull(flags: Int32, user: Api.User, about: String?, settings: Api.PeerSettings, profilePhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId): + if boxed { + buffer.appendInt32(-302941166) + } + serializeInt32(flags, buffer: buffer, boxed: false) + user.serialize(buffer, true) + if Int(flags) & Int(1 << 1) != 0 {serializeString(about!, buffer: buffer, boxed: false)} + settings.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {profilePhoto!.serialize(buffer, true)} + notifySettings.serialize(buffer, true) + if Int(flags) & Int(1 << 3) != 0 {botInfo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} + serializeInt32(commonChatsCount, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId): + return ("userFull", [("flags", flags), ("user", user), ("about", about), ("settings", settings), ("profilePhoto", profilePhoto), ("notifySettings", notifySettings), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("commonChatsCount", commonChatsCount), ("folderId", folderId)]) + } + } + + static func parse_userFull(_ reader: BufferReader) -> UserFull? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.User? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.User + } + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: Api.PeerSettings? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.PeerSettings + } + var _5: Api.Photo? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _6: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + var _7: Api.BotInfo? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.BotInfo + } } + var _8: Int32? + if Int(_1!) & Int(1 << 6) != 0 {_8 = reader.readInt32() } + var _9: Int32? + _9 = reader.readInt32() + var _10: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 6) == 0) || _8 != nil + let _c9 = _9 != nil + let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.UserFull.userFull(flags: _1!, user: _2!, about: _3, settings: _4!, profilePhoto: _5, notifySettings: _6!, botInfo: _7, pinnedMsgId: _8, commonChatsCount: _9!, folderId: _10) + } + else { + return nil + } + } + + } + enum InputChannel: TypeConstructorDescription { + case inputChannelEmpty + case inputChannel(channelId: Int32, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputChannelEmpty: + if boxed { + buffer.appendInt32(-292807034) + } + + break + case .inputChannel(let channelId, let accessHash): + if boxed { + buffer.appendInt32(-1343524562) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputChannelEmpty: + return ("inputChannelEmpty", []) + case .inputChannel(let channelId, let accessHash): + return ("inputChannel", [("channelId", channelId), ("accessHash", accessHash)]) + } + } + + static func parse_inputChannelEmpty(_ reader: BufferReader) -> InputChannel? { + return Api.InputChannel.inputChannelEmpty + } + static func parse_inputChannel(_ reader: BufferReader) -> InputChannel? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputChannel.inputChannel(channelId: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum DcOption: TypeConstructorDescription { + case dcOption(flags: Int32, id: Int32, ipAddress: String, port: Int32, secret: Buffer?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dcOption(let flags, let id, let ipAddress, let port, let secret): + if boxed { + buffer.appendInt32(414687501) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(ipAddress, buffer: buffer, boxed: false) + serializeInt32(port, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 10) != 0 {serializeBytes(secret!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dcOption(let flags, let id, let ipAddress, let port, let secret): + return ("dcOption", [("flags", flags), ("id", id), ("ipAddress", ipAddress), ("port", port), ("secret", secret)]) + } + } + + static func parse_dcOption(_ reader: BufferReader) -> DcOption? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + if Int(_1!) & Int(1 << 10) != 0 {_5 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 10) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.DcOption.dcOption(flags: _1!, id: _2!, ipAddress: _3!, port: _4!, secret: _5) + } + else { + return nil + } + } + + } + enum PollAnswerVoters: TypeConstructorDescription { + case pollAnswerVoters(flags: Int32, option: Buffer, voters: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pollAnswerVoters(let flags, let option, let voters): + if boxed { + buffer.appendInt32(997055186) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeBytes(option, buffer: buffer, boxed: false) + serializeInt32(voters, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pollAnswerVoters(let flags, let option, let voters): + return ("pollAnswerVoters", [("flags", flags), ("option", option), ("voters", voters)]) + } + } + + static func parse_pollAnswerVoters(_ reader: BufferReader) -> PollAnswerVoters? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.PollAnswerVoters.pollAnswerVoters(flags: _1!, option: _2!, voters: _3!) + } + else { + return nil + } + } + + } + enum LangPackLanguage: TypeConstructorDescription { + case langPackLanguage(flags: Int32, name: String, nativeName: String, langCode: String, baseLangCode: String?, pluralCode: String, stringsCount: Int32, translatedCount: Int32, translationsUrl: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl): + if boxed { + buffer.appendInt32(-288727837) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + serializeString(nativeName, buffer: buffer, boxed: false) + serializeString(langCode, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(baseLangCode!, buffer: buffer, boxed: false)} + serializeString(pluralCode, buffer: buffer, boxed: false) + serializeInt32(stringsCount, buffer: buffer, boxed: false) + serializeInt32(translatedCount, buffer: buffer, boxed: false) + serializeString(translationsUrl, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl): + return ("langPackLanguage", [("flags", flags), ("name", name), ("nativeName", nativeName), ("langCode", langCode), ("baseLangCode", baseLangCode), ("pluralCode", pluralCode), ("stringsCount", stringsCount), ("translatedCount", translatedCount), ("translationsUrl", translationsUrl)]) + } + } + + static func parse_langPackLanguage(_ reader: BufferReader) -> LangPackLanguage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } + var _6: String? + _6 = parseString(reader) + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.LangPackLanguage.langPackLanguage(flags: _1!, name: _2!, nativeName: _3!, langCode: _4!, baseLangCode: _5, pluralCode: _6!, stringsCount: _7!, translatedCount: _8!, translationsUrl: _9!) + } + else { + return nil + } + } + + } + enum LangPackDifference: TypeConstructorDescription { + case langPackDifference(langCode: String, fromVersion: Int32, version: Int32, strings: [Api.LangPackString]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .langPackDifference(let langCode, let fromVersion, let version, let strings): + if boxed { + buffer.appendInt32(-209337866) + } + serializeString(langCode, buffer: buffer, boxed: false) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(strings.count)) + for item in strings { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .langPackDifference(let langCode, let fromVersion, let version, let strings): + return ("langPackDifference", [("langCode", langCode), ("fromVersion", fromVersion), ("version", version), ("strings", strings)]) + } + } + + static func parse_langPackDifference(_ reader: BufferReader) -> LangPackDifference? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: [Api.LangPackString]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackString.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.LangPackDifference.langPackDifference(langCode: _1!, fromVersion: _2!, version: _3!, strings: _4!) + } + else { + return nil + } + } + + } + enum WallPaperSettings: TypeConstructorDescription { + case wallPaperSettings(flags: Int32, backgroundColor: Int32?, intensity: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .wallPaperSettings(let flags, let backgroundColor, let intensity): + if boxed { + buffer.appendInt32(-1590738760) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(backgroundColor!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(intensity!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .wallPaperSettings(let flags, let backgroundColor, let intensity): + return ("wallPaperSettings", [("flags", flags), ("backgroundColor", backgroundColor), ("intensity", intensity)]) + } + } + + static func parse_wallPaperSettings(_ reader: BufferReader) -> WallPaperSettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.WallPaperSettings.wallPaperSettings(flags: _1!, backgroundColor: _2, intensity: _3) + } + else { + return nil + } + } + + } + enum EmojiURL: TypeConstructorDescription { + case EmojiURL(url: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .EmojiURL(let url): + if boxed { + buffer.appendInt32(1152191385) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .EmojiURL(let url): + return ("EmojiURL", [("url", url)]) + } + } + + static func parse_EmojiURL(_ reader: BufferReader) -> EmojiURL? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.EmojiURL.EmojiURL(url: _1!) + } + else { + return nil + } + } + + } + enum InputCheckPasswordSRP: TypeConstructorDescription { + case inputCheckPasswordEmpty + case inputCheckPasswordSRP(srpId: Int64, A: Buffer, M1: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputCheckPasswordEmpty: + if boxed { + buffer.appendInt32(-1736378792) + } + + break + case .inputCheckPasswordSRP(let srpId, let A, let M1): + if boxed { + buffer.appendInt32(-763367294) + } + serializeInt64(srpId, buffer: buffer, boxed: false) + serializeBytes(A, buffer: buffer, boxed: false) + serializeBytes(M1, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputCheckPasswordEmpty: + return ("inputCheckPasswordEmpty", []) + case .inputCheckPasswordSRP(let srpId, let A, let M1): + return ("inputCheckPasswordSRP", [("srpId", srpId), ("A", A), ("M1", M1)]) + } + } + + static func parse_inputCheckPasswordEmpty(_ reader: BufferReader) -> InputCheckPasswordSRP? { + return Api.InputCheckPasswordSRP.inputCheckPasswordEmpty + } + static func parse_inputCheckPasswordSRP(_ reader: BufferReader) -> InputCheckPasswordSRP? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputCheckPasswordSRP.inputCheckPasswordSRP(srpId: _1!, A: _2!, M1: _3!) + } + else { + return nil + } + } + + } + enum InputEncryptedFile: TypeConstructorDescription { + case inputEncryptedFileEmpty + case inputEncryptedFileUploaded(id: Int64, parts: Int32, md5Checksum: String, keyFingerprint: Int32) + case inputEncryptedFile(id: Int64, accessHash: Int64) + case inputEncryptedFileBigUploaded(id: Int64, parts: Int32, keyFingerprint: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputEncryptedFileEmpty: + if boxed { + buffer.appendInt32(406307684) + } + + break + case .inputEncryptedFileUploaded(let id, let parts, let md5Checksum, let keyFingerprint): + if boxed { + buffer.appendInt32(1690108678) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(parts, buffer: buffer, boxed: false) + serializeString(md5Checksum, buffer: buffer, boxed: false) + serializeInt32(keyFingerprint, buffer: buffer, boxed: false) + break + case .inputEncryptedFile(let id, let accessHash): + if boxed { + buffer.appendInt32(1511503333) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputEncryptedFileBigUploaded(let id, let parts, let keyFingerprint): + if boxed { + buffer.appendInt32(767652808) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(parts, buffer: buffer, boxed: false) + serializeInt32(keyFingerprint, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputEncryptedFileEmpty: + return ("inputEncryptedFileEmpty", []) + case .inputEncryptedFileUploaded(let id, let parts, let md5Checksum, let keyFingerprint): + return ("inputEncryptedFileUploaded", [("id", id), ("parts", parts), ("md5Checksum", md5Checksum), ("keyFingerprint", keyFingerprint)]) + case .inputEncryptedFile(let id, let accessHash): + return ("inputEncryptedFile", [("id", id), ("accessHash", accessHash)]) + case .inputEncryptedFileBigUploaded(let id, let parts, let keyFingerprint): + return ("inputEncryptedFileBigUploaded", [("id", id), ("parts", parts), ("keyFingerprint", keyFingerprint)]) + } + } + + static func parse_inputEncryptedFileEmpty(_ reader: BufferReader) -> InputEncryptedFile? { + return Api.InputEncryptedFile.inputEncryptedFileEmpty + } + static func parse_inputEncryptedFileUploaded(_ reader: BufferReader) -> InputEncryptedFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputEncryptedFile.inputEncryptedFileUploaded(id: _1!, parts: _2!, md5Checksum: _3!, keyFingerprint: _4!) + } + else { + return nil + } + } + static func parse_inputEncryptedFile(_ reader: BufferReader) -> InputEncryptedFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputEncryptedFile.inputEncryptedFile(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputEncryptedFileBigUploaded(_ reader: BufferReader) -> InputEncryptedFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputEncryptedFile.inputEncryptedFileBigUploaded(id: _1!, parts: _2!, keyFingerprint: _3!) + } + else { + return nil + } + } + + } + enum ExportedMessageLink: TypeConstructorDescription { + case exportedMessageLink(link: String, html: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .exportedMessageLink(let link, let html): + if boxed { + buffer.appendInt32(1571494644) + } + serializeString(link, buffer: buffer, boxed: false) + serializeString(html, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .exportedMessageLink(let link, let html): + return ("exportedMessageLink", [("link", link), ("html", html)]) + } + } + + static func parse_exportedMessageLink(_ reader: BufferReader) -> ExportedMessageLink? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ExportedMessageLink.exportedMessageLink(link: _1!, html: _2!) + } + else { + return nil + } + } + + } + enum InputFile: TypeConstructorDescription { + case inputFile(id: Int64, parts: Int32, name: String, md5Checksum: String) + case inputFileBig(id: Int64, parts: Int32, name: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputFile(let id, let parts, let name, let md5Checksum): + if boxed { + buffer.appendInt32(-181407105) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(parts, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + serializeString(md5Checksum, buffer: buffer, boxed: false) + break + case .inputFileBig(let id, let parts, let name): + if boxed { + buffer.appendInt32(-95482955) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(parts, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputFile(let id, let parts, let name, let md5Checksum): + return ("inputFile", [("id", id), ("parts", parts), ("name", name), ("md5Checksum", md5Checksum)]) + case .inputFileBig(let id, let parts, let name): + return ("inputFileBig", [("id", id), ("parts", parts), ("name", name)]) + } + } + + static func parse_inputFile(_ reader: BufferReader) -> InputFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputFile.inputFile(id: _1!, parts: _2!, name: _3!, md5Checksum: _4!) + } + else { + return nil + } + } + static func parse_inputFileBig(_ reader: BufferReader) -> InputFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputFile.inputFileBig(id: _1!, parts: _2!, name: _3!) + } + else { + return nil + } + } + + } + enum Peer: TypeConstructorDescription { + case peerUser(userId: Int32) + case peerChat(chatId: Int32) + case peerChannel(channelId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .peerUser(let userId): + if boxed { + buffer.appendInt32(-1649296275) + } + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .peerChat(let chatId): + if boxed { + buffer.appendInt32(-1160714821) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + break + case .peerChannel(let channelId): + if boxed { + buffer.appendInt32(-1109531342) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .peerUser(let userId): + return ("peerUser", [("userId", userId)]) + case .peerChat(let chatId): + return ("peerChat", [("chatId", chatId)]) + case .peerChannel(let channelId): + return ("peerChannel", [("channelId", channelId)]) + } + } + + static func parse_peerUser(_ reader: BufferReader) -> Peer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Peer.peerUser(userId: _1!) + } + else { + return nil + } + } + static func parse_peerChat(_ reader: BufferReader) -> Peer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Peer.peerChat(chatId: _1!) + } + else { + return nil + } + } + static func parse_peerChannel(_ reader: BufferReader) -> Peer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Peer.peerChannel(channelId: _1!) + } + else { + return nil + } + } + + } + enum PaymentRequestedInfo: TypeConstructorDescription { + case paymentRequestedInfo(flags: Int32, name: String?, phone: String?, email: String?, shippingAddress: Api.PostAddress?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress): + if boxed { + buffer.appendInt32(-1868808300) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(name!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(phone!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(email!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {shippingAddress!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress): + return ("paymentRequestedInfo", [("flags", flags), ("name", name), ("phone", phone), ("email", email), ("shippingAddress", shippingAddress)]) + } + } + + static func parse_paymentRequestedInfo(_ reader: BufferReader) -> PaymentRequestedInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 2) != 0 {_4 = parseString(reader) } + var _5: Api.PostAddress? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.PostAddress + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PaymentRequestedInfo.paymentRequestedInfo(flags: _1!, name: _2, phone: _3, email: _4, shippingAddress: _5) + } + else { + return nil + } + } + + } + enum UserStatus: TypeConstructorDescription { + case userStatusEmpty + case userStatusOnline(expires: Int32) + case userStatusOffline(wasOnline: Int32) + case userStatusRecently + case userStatusLastWeek + case userStatusLastMonth + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .userStatusEmpty: + if boxed { + buffer.appendInt32(164646985) + } + + break + case .userStatusOnline(let expires): + if boxed { + buffer.appendInt32(-306628279) + } + serializeInt32(expires, buffer: buffer, boxed: false) + break + case .userStatusOffline(let wasOnline): + if boxed { + buffer.appendInt32(9203775) + } + serializeInt32(wasOnline, buffer: buffer, boxed: false) + break + case .userStatusRecently: + if boxed { + buffer.appendInt32(-496024847) + } + + break + case .userStatusLastWeek: + if boxed { + buffer.appendInt32(129960444) + } + + break + case .userStatusLastMonth: + if boxed { + buffer.appendInt32(2011940674) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .userStatusEmpty: + return ("userStatusEmpty", []) + case .userStatusOnline(let expires): + return ("userStatusOnline", [("expires", expires)]) + case .userStatusOffline(let wasOnline): + return ("userStatusOffline", [("wasOnline", wasOnline)]) + case .userStatusRecently: + return ("userStatusRecently", []) + case .userStatusLastWeek: + return ("userStatusLastWeek", []) + case .userStatusLastMonth: + return ("userStatusLastMonth", []) + } + } + + static func parse_userStatusEmpty(_ reader: BufferReader) -> UserStatus? { + return Api.UserStatus.userStatusEmpty + } + static func parse_userStatusOnline(_ reader: BufferReader) -> UserStatus? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.UserStatus.userStatusOnline(expires: _1!) + } + else { + return nil + } + } + static func parse_userStatusOffline(_ reader: BufferReader) -> UserStatus? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.UserStatus.userStatusOffline(wasOnline: _1!) + } + else { + return nil + } + } + static func parse_userStatusRecently(_ reader: BufferReader) -> UserStatus? { + return Api.UserStatus.userStatusRecently + } + static func parse_userStatusLastWeek(_ reader: BufferReader) -> UserStatus? { + return Api.UserStatus.userStatusLastWeek + } + static func parse_userStatusLastMonth(_ reader: BufferReader) -> UserStatus? { + return Api.UserStatus.userStatusLastMonth + } + + } + enum Folder: TypeConstructorDescription { + case folder(flags: Int32, id: Int32, title: String, photo: Api.ChatPhoto?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .folder(let flags, let id, let title, let photo): + if boxed { + buffer.appendInt32(-11252123) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 3) != 0 {photo!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .folder(let flags, let id, let title, let photo): + return ("folder", [("flags", flags), ("id", id), ("title", title), ("photo", photo)]) + } + } + + static func parse_folder(_ reader: BufferReader) -> Folder? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Api.ChatPhoto? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ChatPhoto + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Folder.folder(flags: _1!, id: _2!, title: _3!, photo: _4) + } + else { + return nil + } + } + + } + enum Dialog: TypeConstructorDescription { + case dialog(flags: Int32, peer: Api.Peer, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32, notifySettings: Api.PeerNotifySettings, pts: Int32?, draft: Api.DraftMessage?, folderId: Int32?) + case dialogFolder(flags: Int32, folder: Api.Folder, peer: Api.Peer, topMessage: Int32, unreadMutedPeersCount: Int32, unreadUnmutedPeersCount: Int32, unreadMutedMessagesCount: Int32, unreadUnmutedMessagesCount: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dialog(let flags, let peer, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let notifySettings, let pts, let draft, let folderId): + if boxed { + buffer.appendInt32(739712882) + } + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(topMessage, buffer: buffer, boxed: false) + serializeInt32(readInboxMaxId, buffer: buffer, boxed: false) + serializeInt32(readOutboxMaxId, buffer: buffer, boxed: false) + serializeInt32(unreadCount, buffer: buffer, boxed: false) + serializeInt32(unreadMentionsCount, buffer: buffer, boxed: false) + notifySettings.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(pts!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {draft!.serialize(buffer, true)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + break + case .dialogFolder(let flags, let folder, let peer, let topMessage, let unreadMutedPeersCount, let unreadUnmutedPeersCount, let unreadMutedMessagesCount, let unreadUnmutedMessagesCount): + if boxed { + buffer.appendInt32(1908216652) + } + serializeInt32(flags, buffer: buffer, boxed: false) + folder.serialize(buffer, true) + peer.serialize(buffer, true) + serializeInt32(topMessage, buffer: buffer, boxed: false) + serializeInt32(unreadMutedPeersCount, buffer: buffer, boxed: false) + serializeInt32(unreadUnmutedPeersCount, buffer: buffer, boxed: false) + serializeInt32(unreadMutedMessagesCount, buffer: buffer, boxed: false) + serializeInt32(unreadUnmutedMessagesCount, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dialog(let flags, let peer, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let unreadMentionsCount, let notifySettings, let pts, let draft, let folderId): + return ("dialog", [("flags", flags), ("peer", peer), ("topMessage", topMessage), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("unreadMentionsCount", unreadMentionsCount), ("notifySettings", notifySettings), ("pts", pts), ("draft", draft), ("folderId", folderId)]) + case .dialogFolder(let flags, let folder, let peer, let topMessage, let unreadMutedPeersCount, let unreadUnmutedPeersCount, let unreadMutedMessagesCount, let unreadUnmutedMessagesCount): + return ("dialogFolder", [("flags", flags), ("folder", folder), ("peer", peer), ("topMessage", topMessage), ("unreadMutedPeersCount", unreadMutedPeersCount), ("unreadUnmutedPeersCount", unreadUnmutedPeersCount), ("unreadMutedMessagesCount", unreadMutedMessagesCount), ("unreadUnmutedMessagesCount", unreadUnmutedMessagesCount)]) + } + } + + static func parse_dialog(_ reader: BufferReader) -> Dialog? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Peer? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + var _9: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_9 = reader.readInt32() } + var _10: Api.DraftMessage? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.DraftMessage + } } + var _11: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_11 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 1) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 4) == 0) || _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return Api.Dialog.dialog(flags: _1!, peer: _2!, topMessage: _3!, readInboxMaxId: _4!, readOutboxMaxId: _5!, unreadCount: _6!, unreadMentionsCount: _7!, notifySettings: _8!, pts: _9, draft: _10, folderId: _11) + } + else { + return nil + } + } + static func parse_dialogFolder(_ reader: BufferReader) -> Dialog? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Folder? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Folder + } + var _3: Api.Peer? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.Dialog.dialogFolder(flags: _1!, folder: _2!, peer: _3!, topMessage: _4!, unreadMutedPeersCount: _5!, unreadUnmutedPeersCount: _6!, unreadMutedMessagesCount: _7!, unreadUnmutedMessagesCount: _8!) + } + else { + return nil + } + } + + } + enum SendMessageAction: TypeConstructorDescription { + case sendMessageTypingAction + case sendMessageCancelAction + case sendMessageRecordVideoAction + case sendMessageUploadVideoAction(progress: Int32) + case sendMessageRecordAudioAction + case sendMessageUploadAudioAction(progress: Int32) + case sendMessageUploadPhotoAction(progress: Int32) + case sendMessageUploadDocumentAction(progress: Int32) + case sendMessageGeoLocationAction + case sendMessageChooseContactAction + case sendMessageGamePlayAction + case sendMessageRecordRoundAction + case sendMessageUploadRoundAction(progress: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sendMessageTypingAction: + if boxed { + buffer.appendInt32(381645902) + } + + break + case .sendMessageCancelAction: + if boxed { + buffer.appendInt32(-44119819) + } + + break + case .sendMessageRecordVideoAction: + if boxed { + buffer.appendInt32(-1584933265) + } + + break + case .sendMessageUploadVideoAction(let progress): + if boxed { + buffer.appendInt32(-378127636) + } + serializeInt32(progress, buffer: buffer, boxed: false) + break + case .sendMessageRecordAudioAction: + if boxed { + buffer.appendInt32(-718310409) + } + + break + case .sendMessageUploadAudioAction(let progress): + if boxed { + buffer.appendInt32(-212740181) + } + serializeInt32(progress, buffer: buffer, boxed: false) + break + case .sendMessageUploadPhotoAction(let progress): + if boxed { + buffer.appendInt32(-774682074) + } + serializeInt32(progress, buffer: buffer, boxed: false) + break + case .sendMessageUploadDocumentAction(let progress): + if boxed { + buffer.appendInt32(-1441998364) + } + serializeInt32(progress, buffer: buffer, boxed: false) + break + case .sendMessageGeoLocationAction: + if boxed { + buffer.appendInt32(393186209) + } + + break + case .sendMessageChooseContactAction: + if boxed { + buffer.appendInt32(1653390447) + } + + break + case .sendMessageGamePlayAction: + if boxed { + buffer.appendInt32(-580219064) + } + + break + case .sendMessageRecordRoundAction: + if boxed { + buffer.appendInt32(-1997373508) + } + + break + case .sendMessageUploadRoundAction(let progress): + if boxed { + buffer.appendInt32(608050278) + } + serializeInt32(progress, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sendMessageTypingAction: + return ("sendMessageTypingAction", []) + case .sendMessageCancelAction: + return ("sendMessageCancelAction", []) + case .sendMessageRecordVideoAction: + return ("sendMessageRecordVideoAction", []) + case .sendMessageUploadVideoAction(let progress): + return ("sendMessageUploadVideoAction", [("progress", progress)]) + case .sendMessageRecordAudioAction: + return ("sendMessageRecordAudioAction", []) + case .sendMessageUploadAudioAction(let progress): + return ("sendMessageUploadAudioAction", [("progress", progress)]) + case .sendMessageUploadPhotoAction(let progress): + return ("sendMessageUploadPhotoAction", [("progress", progress)]) + case .sendMessageUploadDocumentAction(let progress): + return ("sendMessageUploadDocumentAction", [("progress", progress)]) + case .sendMessageGeoLocationAction: + return ("sendMessageGeoLocationAction", []) + case .sendMessageChooseContactAction: + return ("sendMessageChooseContactAction", []) + case .sendMessageGamePlayAction: + return ("sendMessageGamePlayAction", []) + case .sendMessageRecordRoundAction: + return ("sendMessageRecordRoundAction", []) + case .sendMessageUploadRoundAction(let progress): + return ("sendMessageUploadRoundAction", [("progress", progress)]) + } + } + + static func parse_sendMessageTypingAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageTypingAction + } + static func parse_sendMessageCancelAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageCancelAction + } + static func parse_sendMessageRecordVideoAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageRecordVideoAction + } + static func parse_sendMessageUploadVideoAction(_ reader: BufferReader) -> SendMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.SendMessageAction.sendMessageUploadVideoAction(progress: _1!) + } + else { + return nil + } + } + static func parse_sendMessageRecordAudioAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageRecordAudioAction + } + static func parse_sendMessageUploadAudioAction(_ reader: BufferReader) -> SendMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.SendMessageAction.sendMessageUploadAudioAction(progress: _1!) + } + else { + return nil + } + } + static func parse_sendMessageUploadPhotoAction(_ reader: BufferReader) -> SendMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.SendMessageAction.sendMessageUploadPhotoAction(progress: _1!) + } + else { + return nil + } + } + static func parse_sendMessageUploadDocumentAction(_ reader: BufferReader) -> SendMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.SendMessageAction.sendMessageUploadDocumentAction(progress: _1!) + } + else { + return nil + } + } + static func parse_sendMessageGeoLocationAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageGeoLocationAction + } + static func parse_sendMessageChooseContactAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageChooseContactAction + } + static func parse_sendMessageGamePlayAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageGamePlayAction + } + static func parse_sendMessageRecordRoundAction(_ reader: BufferReader) -> SendMessageAction? { + return Api.SendMessageAction.sendMessageRecordRoundAction + } + static func parse_sendMessageUploadRoundAction(_ reader: BufferReader) -> SendMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.SendMessageAction.sendMessageUploadRoundAction(progress: _1!) + } + else { + return nil + } + } + + } + enum PrivacyKey: TypeConstructorDescription { + case privacyKeyStatusTimestamp + case privacyKeyChatInvite + case privacyKeyPhoneCall + case privacyKeyPhoneP2P + case privacyKeyForwards + case privacyKeyProfilePhoto + case privacyKeyPhoneNumber + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .privacyKeyStatusTimestamp: + if boxed { + buffer.appendInt32(-1137792208) + } + + break + case .privacyKeyChatInvite: + if boxed { + buffer.appendInt32(1343122938) + } + + break + case .privacyKeyPhoneCall: + if boxed { + buffer.appendInt32(1030105979) + } + + break + case .privacyKeyPhoneP2P: + if boxed { + buffer.appendInt32(961092808) + } + + break + case .privacyKeyForwards: + if boxed { + buffer.appendInt32(1777096355) + } + + break + case .privacyKeyProfilePhoto: + if boxed { + buffer.appendInt32(-1777000467) + } + + break + case .privacyKeyPhoneNumber: + if boxed { + buffer.appendInt32(-778378131) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .privacyKeyStatusTimestamp: + return ("privacyKeyStatusTimestamp", []) + case .privacyKeyChatInvite: + return ("privacyKeyChatInvite", []) + case .privacyKeyPhoneCall: + return ("privacyKeyPhoneCall", []) + case .privacyKeyPhoneP2P: + return ("privacyKeyPhoneP2P", []) + case .privacyKeyForwards: + return ("privacyKeyForwards", []) + case .privacyKeyProfilePhoto: + return ("privacyKeyProfilePhoto", []) + case .privacyKeyPhoneNumber: + return ("privacyKeyPhoneNumber", []) + } + } + + static func parse_privacyKeyStatusTimestamp(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyStatusTimestamp + } + static func parse_privacyKeyChatInvite(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyChatInvite + } + static func parse_privacyKeyPhoneCall(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyPhoneCall + } + static func parse_privacyKeyPhoneP2P(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyPhoneP2P + } + static func parse_privacyKeyForwards(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyForwards + } + static func parse_privacyKeyProfilePhoto(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyProfilePhoto + } + static func parse_privacyKeyPhoneNumber(_ reader: BufferReader) -> PrivacyKey? { + return Api.PrivacyKey.privacyKeyPhoneNumber + } + + } + enum Update: TypeConstructorDescription { + case updateNewMessage(message: Api.Message, pts: Int32, ptsCount: Int32) + case updateMessageID(id: Int32, randomId: Int64) + case updateDeleteMessages(messages: [Int32], pts: Int32, ptsCount: Int32) + case updateUserTyping(userId: Int32, action: Api.SendMessageAction) + case updateChatUserTyping(chatId: Int32, userId: Int32, action: Api.SendMessageAction) + case updateChatParticipants(participants: Api.ChatParticipants) + case updateUserStatus(userId: Int32, status: Api.UserStatus) + case updateUserName(userId: Int32, firstName: String, lastName: String, username: String) + case updateUserPhoto(userId: Int32, date: Int32, photo: Api.UserProfilePhoto, previous: Api.Bool) + case updateContactLink(userId: Int32, myLink: Api.ContactLink, foreignLink: Api.ContactLink) + case updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32) + case updateEncryptedChatTyping(chatId: Int32) + case updateEncryption(chat: Api.EncryptedChat, date: Int32) + case updateEncryptedMessagesRead(chatId: Int32, maxDate: Int32, date: Int32) + case updateChatParticipantAdd(chatId: Int32, userId: Int32, inviterId: Int32, date: Int32, version: Int32) + case updateChatParticipantDelete(chatId: Int32, userId: Int32, version: Int32) + case updateDcOptions(dcOptions: [Api.DcOption]) + case updateUserBlocked(userId: Int32, blocked: Api.Bool) + case updateNotifySettings(peer: Api.NotifyPeer, notifySettings: Api.PeerNotifySettings) + case updateServiceNotification(flags: Int32, inboxDate: Int32?, type: String, message: String, media: Api.MessageMedia, entities: [Api.MessageEntity]) + case updatePrivacy(key: Api.PrivacyKey, rules: [Api.PrivacyRule]) + case updateUserPhone(userId: Int32, phone: String) + case updateReadHistoryOutbox(peer: Api.Peer, maxId: Int32, pts: Int32, ptsCount: Int32) + case updateWebPage(webpage: Api.WebPage, pts: Int32, ptsCount: Int32) + case updateReadMessagesContents(messages: [Int32], pts: Int32, ptsCount: Int32) + case updateChannelTooLong(flags: Int32, channelId: Int32, pts: Int32?) + case updateChannel(channelId: Int32) + case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32) + case updateDeleteChannelMessages(channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32) + case updateChannelMessageViews(channelId: Int32, id: Int32, views: Int32) + case updateChatParticipantAdmin(chatId: Int32, userId: Int32, isAdmin: Api.Bool, version: Int32) + case updateNewStickerSet(stickerset: Api.messages.StickerSet) + case updateStickerSetsOrder(flags: Int32, order: [Int64]) + case updateStickerSets + case updateSavedGifs + case updateBotInlineQuery(flags: Int32, queryId: Int64, userId: Int32, query: String, geo: Api.GeoPoint?, offset: String) + case updateBotInlineSend(flags: Int32, userId: Int32, query: String, geo: Api.GeoPoint?, id: String, msgId: Api.InputBotInlineMessageID?) + case updateEditChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32) + case updateChannelPinnedMessage(channelId: Int32, id: Int32) + case updateBotCallbackQuery(flags: Int32, queryId: Int64, userId: Int32, peer: Api.Peer, msgId: Int32, chatInstance: Int64, data: Buffer?, gameShortName: String?) + case updateEditMessage(message: Api.Message, pts: Int32, ptsCount: Int32) + case updateInlineBotCallbackQuery(flags: Int32, queryId: Int64, userId: Int32, msgId: Api.InputBotInlineMessageID, chatInstance: Int64, data: Buffer?, gameShortName: String?) + case updateReadChannelOutbox(channelId: Int32, maxId: Int32) + case updateDraftMessage(peer: Api.Peer, draft: Api.DraftMessage) + case updateReadFeaturedStickers + case updateRecentStickers + case updateConfig + case updatePtsChanged + case updateChannelWebPage(channelId: Int32, webpage: Api.WebPage, pts: Int32, ptsCount: Int32) + case updateBotWebhookJSON(data: Api.DataJSON) + case updateBotWebhookJSONQuery(queryId: Int64, data: Api.DataJSON, timeout: Int32) + case updateBotShippingQuery(queryId: Int64, userId: Int32, payload: Buffer, shippingAddress: Api.PostAddress) + case updateBotPrecheckoutQuery(flags: Int32, queryId: Int64, userId: Int32, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, currency: String, totalAmount: Int64) + case updatePhoneCall(phoneCall: Api.PhoneCall) + case updateLangPack(difference: Api.LangPackDifference) + case updateFavedStickers + case updateChannelReadMessagesContents(channelId: Int32, messages: [Int32]) + case updateContactsReset + case updateChannelAvailableMessages(channelId: Int32, availableMinId: Int32) + case updateDialogUnreadMark(flags: Int32, peer: Api.DialogPeer) + case updateLangPackTooLong(langCode: String) + case updateUserPinnedMessage(userId: Int32, id: Int32) + case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults) + case updateChatDefaultBannedRights(peer: Api.Peer, defaultBannedRights: Api.ChatBannedRights, version: Int32) + case updateChatPinnedMessage(chatId: Int32, id: Int32, version: Int32) + case updateFolderPeers(folderPeers: [Api.FolderPeer], pts: Int32, ptsCount: Int32) + case updateDialogPinned(flags: Int32, folderId: Int32?, peer: Api.DialogPeer) + case updatePinnedDialogs(flags: Int32, folderId: Int32?, order: [Api.DialogPeer]?) + case updateReadChannelInbox(flags: Int32, folderId: Int32?, channelId: Int32, maxId: Int32, stillUnreadCount: Int32, pts: Int32) + case updateReadHistoryInbox(flags: Int32, folderId: Int32?, peer: Api.Peer, maxId: Int32, stillUnreadCount: Int32, pts: Int32, ptsCount: Int32) + case updatePeerSettings(peer: Api.Peer, settings: Api.PeerSettings) + case updateContactLocated(contacts: [Api.ContactLocated]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .updateNewMessage(let message, let pts, let ptsCount): + if boxed { + buffer.appendInt32(522914557) + } + message.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateMessageID(let id, let randomId): + if boxed { + buffer.appendInt32(1318109142) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + break + case .updateDeleteMessages(let messages, let pts, let ptsCount): + if boxed { + buffer.appendInt32(-1576161051) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + serializeInt32(item, buffer: buffer, boxed: false) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateUserTyping(let userId, let action): + if boxed { + buffer.appendInt32(1548249383) + } + serializeInt32(userId, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + case .updateChatUserTyping(let chatId, let userId, let action): + if boxed { + buffer.appendInt32(-1704596961) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + case .updateChatParticipants(let participants): + if boxed { + buffer.appendInt32(125178264) + } + participants.serialize(buffer, true) + break + case .updateUserStatus(let userId, let status): + if boxed { + buffer.appendInt32(469489699) + } + serializeInt32(userId, buffer: buffer, boxed: false) + status.serialize(buffer, true) + break + case .updateUserName(let userId, let firstName, let lastName, let username): + if boxed { + buffer.appendInt32(-1489818765) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(username, buffer: buffer, boxed: false) + break + case .updateUserPhoto(let userId, let date, let photo, let previous): + if boxed { + buffer.appendInt32(-1791935732) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + previous.serialize(buffer, true) + break + case .updateContactLink(let userId, let myLink, let foreignLink): + if boxed { + buffer.appendInt32(-1657903163) + } + serializeInt32(userId, buffer: buffer, boxed: false) + myLink.serialize(buffer, true) + foreignLink.serialize(buffer, true) + break + case .updateNewEncryptedMessage(let message, let qts): + if boxed { + buffer.appendInt32(314359194) + } + message.serialize(buffer, true) + serializeInt32(qts, buffer: buffer, boxed: false) + break + case .updateEncryptedChatTyping(let chatId): + if boxed { + buffer.appendInt32(386986326) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + break + case .updateEncryption(let chat, let date): + if boxed { + buffer.appendInt32(-1264392051) + } + chat.serialize(buffer, true) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .updateEncryptedMessagesRead(let chatId, let maxDate, let date): + if boxed { + buffer.appendInt32(956179895) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(maxDate, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .updateChatParticipantAdd(let chatId, let userId, let inviterId, let date, let version): + if boxed { + buffer.appendInt32(-364179876) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(inviterId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + break + case .updateChatParticipantDelete(let chatId, let userId, let version): + if boxed { + buffer.appendInt32(1851755554) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + break + case .updateDcOptions(let dcOptions): + if boxed { + buffer.appendInt32(-1906403213) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dcOptions.count)) + for item in dcOptions { + item.serialize(buffer, true) + } + break + case .updateUserBlocked(let userId, let blocked): + if boxed { + buffer.appendInt32(-2131957734) + } + serializeInt32(userId, buffer: buffer, boxed: false) + blocked.serialize(buffer, true) + break + case .updateNotifySettings(let peer, let notifySettings): + if boxed { + buffer.appendInt32(-1094555409) + } + peer.serialize(buffer, true) + notifySettings.serialize(buffer, true) + break + case .updateServiceNotification(let flags, let inboxDate, let type, let message, let media, let entities): + if boxed { + buffer.appendInt32(-337352679) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(inboxDate!, buffer: buffer, boxed: false)} + serializeString(type, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + media.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities.count)) + for item in entities { + item.serialize(buffer, true) + } + break + case .updatePrivacy(let key, let rules): + if boxed { + buffer.appendInt32(-298113238) + } + key.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rules.count)) + for item in rules { + item.serialize(buffer, true) + } + break + case .updateUserPhone(let userId, let phone): + if boxed { + buffer.appendInt32(314130811) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(phone, buffer: buffer, boxed: false) + break + case .updateReadHistoryOutbox(let peer, let maxId, let pts, let ptsCount): + if boxed { + buffer.appendInt32(791617983) + } + peer.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateWebPage(let webpage, let pts, let ptsCount): + if boxed { + buffer.appendInt32(2139689491) + } + webpage.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateReadMessagesContents(let messages, let pts, let ptsCount): + if boxed { + buffer.appendInt32(1757493555) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + serializeInt32(item, buffer: buffer, boxed: false) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateChannelTooLong(let flags, let channelId, let pts): + if boxed { + buffer.appendInt32(-352032773) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(channelId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(pts!, buffer: buffer, boxed: false)} + break + case .updateChannel(let channelId): + if boxed { + buffer.appendInt32(-1227598250) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + break + case .updateNewChannelMessage(let message, let pts, let ptsCount): + if boxed { + buffer.appendInt32(1656358105) + } + message.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateDeleteChannelMessages(let channelId, let messages, let pts, let ptsCount): + if boxed { + buffer.appendInt32(-1015733815) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + serializeInt32(item, buffer: buffer, boxed: false) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateChannelMessageViews(let channelId, let id, let views): + if boxed { + buffer.appendInt32(-1734268085) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(views, buffer: buffer, boxed: false) + break + case .updateChatParticipantAdmin(let chatId, let userId, let isAdmin, let version): + if boxed { + buffer.appendInt32(-1232070311) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + isAdmin.serialize(buffer, true) + serializeInt32(version, buffer: buffer, boxed: false) + break + case .updateNewStickerSet(let stickerset): + if boxed { + buffer.appendInt32(1753886890) + } + stickerset.serialize(buffer, true) + break + case .updateStickerSetsOrder(let flags, let order): + if boxed { + buffer.appendInt32(196268545) + } + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .updateStickerSets: + if boxed { + buffer.appendInt32(1135492588) + } + + break + case .updateSavedGifs: + if boxed { + buffer.appendInt32(-1821035490) + } + + break + case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let offset): + if boxed { + buffer.appendInt32(1417832080) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(query, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {geo!.serialize(buffer, true)} + serializeString(offset, buffer: buffer, boxed: false) + break + case .updateBotInlineSend(let flags, let userId, let query, let geo, let id, let msgId): + if boxed { + buffer.appendInt32(239663460) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(query, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {geo!.serialize(buffer, true)} + serializeString(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {msgId!.serialize(buffer, true)} + break + case .updateEditChannelMessage(let message, let pts, let ptsCount): + if boxed { + buffer.appendInt32(457133559) + } + message.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateChannelPinnedMessage(let channelId, let id): + if boxed { + buffer.appendInt32(-1738988427) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + break + case .updateBotCallbackQuery(let flags, let queryId, let userId, let peer, let msgId, let chatInstance, let data, let gameShortName): + if boxed { + buffer.appendInt32(-415938591) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + serializeInt64(chatInstance, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(data!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(gameShortName!, buffer: buffer, boxed: false)} + break + case .updateEditMessage(let message, let pts, let ptsCount): + if boxed { + buffer.appendInt32(-469536605) + } + message.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateInlineBotCallbackQuery(let flags, let queryId, let userId, let msgId, let chatInstance, let data, let gameShortName): + if boxed { + buffer.appendInt32(-103646630) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + msgId.serialize(buffer, true) + serializeInt64(chatInstance, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(data!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(gameShortName!, buffer: buffer, boxed: false)} + break + case .updateReadChannelOutbox(let channelId, let maxId): + if boxed { + buffer.appendInt32(634833351) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + break + case .updateDraftMessage(let peer, let draft): + if boxed { + buffer.appendInt32(-299124375) + } + peer.serialize(buffer, true) + draft.serialize(buffer, true) + break + case .updateReadFeaturedStickers: + if boxed { + buffer.appendInt32(1461528386) + } + + break + case .updateRecentStickers: + if boxed { + buffer.appendInt32(-1706939360) + } + + break + case .updateConfig: + if boxed { + buffer.appendInt32(-1574314746) + } + + break + case .updatePtsChanged: + if boxed { + buffer.appendInt32(861169551) + } + + break + case .updateChannelWebPage(let channelId, let webpage, let pts, let ptsCount): + if boxed { + buffer.appendInt32(1081547008) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + webpage.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateBotWebhookJSON(let data): + if boxed { + buffer.appendInt32(-2095595325) + } + data.serialize(buffer, true) + break + case .updateBotWebhookJSONQuery(let queryId, let data, let timeout): + if boxed { + buffer.appendInt32(-1684914010) + } + serializeInt64(queryId, buffer: buffer, boxed: false) + data.serialize(buffer, true) + serializeInt32(timeout, buffer: buffer, boxed: false) + break + case .updateBotShippingQuery(let queryId, let userId, let payload, let shippingAddress): + if boxed { + buffer.appendInt32(-523384512) + } + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeBytes(payload, buffer: buffer, boxed: false) + shippingAddress.serialize(buffer, true) + break + case .updateBotPrecheckoutQuery(let flags, let queryId, let userId, let payload, let info, let shippingOptionId, let currency, let totalAmount): + if boxed { + buffer.appendInt32(1563376297) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeBytes(payload, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {info!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(shippingOptionId!, buffer: buffer, boxed: false)} + serializeString(currency, buffer: buffer, boxed: false) + serializeInt64(totalAmount, buffer: buffer, boxed: false) + break + case .updatePhoneCall(let phoneCall): + if boxed { + buffer.appendInt32(-1425052898) + } + phoneCall.serialize(buffer, true) + break + case .updateLangPack(let difference): + if boxed { + buffer.appendInt32(1442983757) + } + difference.serialize(buffer, true) + break + case .updateFavedStickers: + if boxed { + buffer.appendInt32(-451831443) + } + + break + case .updateChannelReadMessagesContents(let channelId, let messages): + if boxed { + buffer.appendInt32(-1987495099) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .updateContactsReset: + if boxed { + buffer.appendInt32(1887741886) + } + + break + case .updateChannelAvailableMessages(let channelId, let availableMinId): + if boxed { + buffer.appendInt32(1893427255) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt32(availableMinId, buffer: buffer, boxed: false) + break + case .updateDialogUnreadMark(let flags, let peer): + if boxed { + buffer.appendInt32(-513517117) + } + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + break + case .updateLangPackTooLong(let langCode): + if boxed { + buffer.appendInt32(1180041828) + } + serializeString(langCode, buffer: buffer, boxed: false) + break + case .updateUserPinnedMessage(let userId, let id): + if boxed { + buffer.appendInt32(1279515160) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + break + case .updateMessagePoll(let flags, let pollId, let poll, let results): + if boxed { + buffer.appendInt32(-1398708869) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(pollId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {poll!.serialize(buffer, true)} + results.serialize(buffer, true) + break + case .updateChatDefaultBannedRights(let peer, let defaultBannedRights, let version): + if boxed { + buffer.appendInt32(1421875280) + } + peer.serialize(buffer, true) + defaultBannedRights.serialize(buffer, true) + serializeInt32(version, buffer: buffer, boxed: false) + break + case .updateChatPinnedMessage(let chatId, let id, let version): + if boxed { + buffer.appendInt32(-519195831) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + break + case .updateFolderPeers(let folderPeers, let pts, let ptsCount): + if boxed { + buffer.appendInt32(422972864) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(folderPeers.count)) + for item in folderPeers { + item.serialize(buffer, true) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updateDialogPinned(let flags, let folderId, let peer): + if boxed { + buffer.appendInt32(1852826908) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + peer.serialize(buffer, true) + break + case .updatePinnedDialogs(let flags, let folderId, let order): + if boxed { + buffer.appendInt32(-99664734) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order!.count)) + for item in order! { + item.serialize(buffer, true) + }} + break + case .updateReadChannelInbox(let flags, let folderId, let channelId, let maxId, let stillUnreadCount, let pts): + if boxed { + buffer.appendInt32(856380452) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(stillUnreadCount, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + break + case .updateReadHistoryInbox(let flags, let folderId, let peer, let maxId, let stillUnreadCount, let pts, let ptsCount): + if boxed { + buffer.appendInt32(-1667805217) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + peer.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(stillUnreadCount, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + break + case .updatePeerSettings(let peer, let settings): + if boxed { + buffer.appendInt32(1786671974) + } + peer.serialize(buffer, true) + settings.serialize(buffer, true) + break + case .updateContactLocated(let contacts): + if boxed { + buffer.appendInt32(1602468195) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(contacts.count)) + for item in contacts { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .updateNewMessage(let message, let pts, let ptsCount): + return ("updateNewMessage", [("message", message), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateMessageID(let id, let randomId): + return ("updateMessageID", [("id", id), ("randomId", randomId)]) + case .updateDeleteMessages(let messages, let pts, let ptsCount): + return ("updateDeleteMessages", [("messages", messages), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateUserTyping(let userId, let action): + return ("updateUserTyping", [("userId", userId), ("action", action)]) + case .updateChatUserTyping(let chatId, let userId, let action): + return ("updateChatUserTyping", [("chatId", chatId), ("userId", userId), ("action", action)]) + case .updateChatParticipants(let participants): + return ("updateChatParticipants", [("participants", participants)]) + case .updateUserStatus(let userId, let status): + return ("updateUserStatus", [("userId", userId), ("status", status)]) + case .updateUserName(let userId, let firstName, let lastName, let username): + return ("updateUserName", [("userId", userId), ("firstName", firstName), ("lastName", lastName), ("username", username)]) + case .updateUserPhoto(let userId, let date, let photo, let previous): + return ("updateUserPhoto", [("userId", userId), ("date", date), ("photo", photo), ("previous", previous)]) + case .updateContactLink(let userId, let myLink, let foreignLink): + return ("updateContactLink", [("userId", userId), ("myLink", myLink), ("foreignLink", foreignLink)]) + case .updateNewEncryptedMessage(let message, let qts): + return ("updateNewEncryptedMessage", [("message", message), ("qts", qts)]) + case .updateEncryptedChatTyping(let chatId): + return ("updateEncryptedChatTyping", [("chatId", chatId)]) + case .updateEncryption(let chat, let date): + return ("updateEncryption", [("chat", chat), ("date", date)]) + case .updateEncryptedMessagesRead(let chatId, let maxDate, let date): + return ("updateEncryptedMessagesRead", [("chatId", chatId), ("maxDate", maxDate), ("date", date)]) + case .updateChatParticipantAdd(let chatId, let userId, let inviterId, let date, let version): + return ("updateChatParticipantAdd", [("chatId", chatId), ("userId", userId), ("inviterId", inviterId), ("date", date), ("version", version)]) + case .updateChatParticipantDelete(let chatId, let userId, let version): + return ("updateChatParticipantDelete", [("chatId", chatId), ("userId", userId), ("version", version)]) + case .updateDcOptions(let dcOptions): + return ("updateDcOptions", [("dcOptions", dcOptions)]) + case .updateUserBlocked(let userId, let blocked): + return ("updateUserBlocked", [("userId", userId), ("blocked", blocked)]) + case .updateNotifySettings(let peer, let notifySettings): + return ("updateNotifySettings", [("peer", peer), ("notifySettings", notifySettings)]) + case .updateServiceNotification(let flags, let inboxDate, let type, let message, let media, let entities): + return ("updateServiceNotification", [("flags", flags), ("inboxDate", inboxDate), ("type", type), ("message", message), ("media", media), ("entities", entities)]) + case .updatePrivacy(let key, let rules): + return ("updatePrivacy", [("key", key), ("rules", rules)]) + case .updateUserPhone(let userId, let phone): + return ("updateUserPhone", [("userId", userId), ("phone", phone)]) + case .updateReadHistoryOutbox(let peer, let maxId, let pts, let ptsCount): + return ("updateReadHistoryOutbox", [("peer", peer), ("maxId", maxId), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateWebPage(let webpage, let pts, let ptsCount): + return ("updateWebPage", [("webpage", webpage), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateReadMessagesContents(let messages, let pts, let ptsCount): + return ("updateReadMessagesContents", [("messages", messages), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateChannelTooLong(let flags, let channelId, let pts): + return ("updateChannelTooLong", [("flags", flags), ("channelId", channelId), ("pts", pts)]) + case .updateChannel(let channelId): + return ("updateChannel", [("channelId", channelId)]) + case .updateNewChannelMessage(let message, let pts, let ptsCount): + return ("updateNewChannelMessage", [("message", message), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateDeleteChannelMessages(let channelId, let messages, let pts, let ptsCount): + return ("updateDeleteChannelMessages", [("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateChannelMessageViews(let channelId, let id, let views): + return ("updateChannelMessageViews", [("channelId", channelId), ("id", id), ("views", views)]) + case .updateChatParticipantAdmin(let chatId, let userId, let isAdmin, let version): + return ("updateChatParticipantAdmin", [("chatId", chatId), ("userId", userId), ("isAdmin", isAdmin), ("version", version)]) + case .updateNewStickerSet(let stickerset): + return ("updateNewStickerSet", [("stickerset", stickerset)]) + case .updateStickerSetsOrder(let flags, let order): + return ("updateStickerSetsOrder", [("flags", flags), ("order", order)]) + case .updateStickerSets: + return ("updateStickerSets", []) + case .updateSavedGifs: + return ("updateSavedGifs", []) + case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let offset): + return ("updateBotInlineQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("query", query), ("geo", geo), ("offset", offset)]) + case .updateBotInlineSend(let flags, let userId, let query, let geo, let id, let msgId): + return ("updateBotInlineSend", [("flags", flags), ("userId", userId), ("query", query), ("geo", geo), ("id", id), ("msgId", msgId)]) + case .updateEditChannelMessage(let message, let pts, let ptsCount): + return ("updateEditChannelMessage", [("message", message), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateChannelPinnedMessage(let channelId, let id): + return ("updateChannelPinnedMessage", [("channelId", channelId), ("id", id)]) + case .updateBotCallbackQuery(let flags, let queryId, let userId, let peer, let msgId, let chatInstance, let data, let gameShortName): + return ("updateBotCallbackQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("peer", peer), ("msgId", msgId), ("chatInstance", chatInstance), ("data", data), ("gameShortName", gameShortName)]) + case .updateEditMessage(let message, let pts, let ptsCount): + return ("updateEditMessage", [("message", message), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateInlineBotCallbackQuery(let flags, let queryId, let userId, let msgId, let chatInstance, let data, let gameShortName): + return ("updateInlineBotCallbackQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("msgId", msgId), ("chatInstance", chatInstance), ("data", data), ("gameShortName", gameShortName)]) + case .updateReadChannelOutbox(let channelId, let maxId): + return ("updateReadChannelOutbox", [("channelId", channelId), ("maxId", maxId)]) + case .updateDraftMessage(let peer, let draft): + return ("updateDraftMessage", [("peer", peer), ("draft", draft)]) + case .updateReadFeaturedStickers: + return ("updateReadFeaturedStickers", []) + case .updateRecentStickers: + return ("updateRecentStickers", []) + case .updateConfig: + return ("updateConfig", []) + case .updatePtsChanged: + return ("updatePtsChanged", []) + case .updateChannelWebPage(let channelId, let webpage, let pts, let ptsCount): + return ("updateChannelWebPage", [("channelId", channelId), ("webpage", webpage), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateBotWebhookJSON(let data): + return ("updateBotWebhookJSON", [("data", data)]) + case .updateBotWebhookJSONQuery(let queryId, let data, let timeout): + return ("updateBotWebhookJSONQuery", [("queryId", queryId), ("data", data), ("timeout", timeout)]) + case .updateBotShippingQuery(let queryId, let userId, let payload, let shippingAddress): + return ("updateBotShippingQuery", [("queryId", queryId), ("userId", userId), ("payload", payload), ("shippingAddress", shippingAddress)]) + case .updateBotPrecheckoutQuery(let flags, let queryId, let userId, let payload, let info, let shippingOptionId, let currency, let totalAmount): + return ("updateBotPrecheckoutQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("payload", payload), ("info", info), ("shippingOptionId", shippingOptionId), ("currency", currency), ("totalAmount", totalAmount)]) + case .updatePhoneCall(let phoneCall): + return ("updatePhoneCall", [("phoneCall", phoneCall)]) + case .updateLangPack(let difference): + return ("updateLangPack", [("difference", difference)]) + case .updateFavedStickers: + return ("updateFavedStickers", []) + case .updateChannelReadMessagesContents(let channelId, let messages): + return ("updateChannelReadMessagesContents", [("channelId", channelId), ("messages", messages)]) + case .updateContactsReset: + return ("updateContactsReset", []) + case .updateChannelAvailableMessages(let channelId, let availableMinId): + return ("updateChannelAvailableMessages", [("channelId", channelId), ("availableMinId", availableMinId)]) + case .updateDialogUnreadMark(let flags, let peer): + return ("updateDialogUnreadMark", [("flags", flags), ("peer", peer)]) + case .updateLangPackTooLong(let langCode): + return ("updateLangPackTooLong", [("langCode", langCode)]) + case .updateUserPinnedMessage(let userId, let id): + return ("updateUserPinnedMessage", [("userId", userId), ("id", id)]) + case .updateMessagePoll(let flags, let pollId, let poll, let results): + return ("updateMessagePoll", [("flags", flags), ("pollId", pollId), ("poll", poll), ("results", results)]) + case .updateChatDefaultBannedRights(let peer, let defaultBannedRights, let version): + return ("updateChatDefaultBannedRights", [("peer", peer), ("defaultBannedRights", defaultBannedRights), ("version", version)]) + case .updateChatPinnedMessage(let chatId, let id, let version): + return ("updateChatPinnedMessage", [("chatId", chatId), ("id", id), ("version", version)]) + case .updateFolderPeers(let folderPeers, let pts, let ptsCount): + return ("updateFolderPeers", [("folderPeers", folderPeers), ("pts", pts), ("ptsCount", ptsCount)]) + case .updateDialogPinned(let flags, let folderId, let peer): + return ("updateDialogPinned", [("flags", flags), ("folderId", folderId), ("peer", peer)]) + case .updatePinnedDialogs(let flags, let folderId, let order): + return ("updatePinnedDialogs", [("flags", flags), ("folderId", folderId), ("order", order)]) + case .updateReadChannelInbox(let flags, let folderId, let channelId, let maxId, let stillUnreadCount, let pts): + return ("updateReadChannelInbox", [("flags", flags), ("folderId", folderId), ("channelId", channelId), ("maxId", maxId), ("stillUnreadCount", stillUnreadCount), ("pts", pts)]) + case .updateReadHistoryInbox(let flags, let folderId, let peer, let maxId, let stillUnreadCount, let pts, let ptsCount): + return ("updateReadHistoryInbox", [("flags", flags), ("folderId", folderId), ("peer", peer), ("maxId", maxId), ("stillUnreadCount", stillUnreadCount), ("pts", pts), ("ptsCount", ptsCount)]) + case .updatePeerSettings(let peer, let settings): + return ("updatePeerSettings", [("peer", peer), ("settings", settings)]) + case .updateContactLocated(let contacts): + return ("updateContactLocated", [("contacts", contacts)]) + } + } + + static func parse_updateNewMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateNewMessage(message: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateMessageID(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateMessageID(id: _1!, randomId: _2!) + } + else { + return nil + } + } + static func parse_updateDeleteMessages(_ reader: BufferReader) -> Update? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateDeleteMessages(messages: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateUserTyping(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SendMessageAction? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SendMessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateUserTyping(userId: _1!, action: _2!) + } + else { + return nil + } + } + static func parse_updateChatUserTyping(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.SendMessageAction? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.SendMessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChatUserTyping(chatId: _1!, userId: _2!, action: _3!) + } + else { + return nil + } + } + static func parse_updateChatParticipants(_ reader: BufferReader) -> Update? { + var _1: Api.ChatParticipants? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChatParticipants + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateChatParticipants(participants: _1!) + } + else { + return nil + } + } + static func parse_updateUserStatus(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.UserStatus? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.UserStatus + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateUserStatus(userId: _1!, status: _2!) + } + else { + return nil + } + } + static func parse_updateUserName(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateUserName(userId: _1!, firstName: _2!, lastName: _3!, username: _4!) + } + else { + return nil + } + } + static func parse_updateUserPhoto(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.UserProfilePhoto? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.UserProfilePhoto + } + var _4: Api.Bool? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateUserPhoto(userId: _1!, date: _2!, photo: _3!, previous: _4!) + } + else { + return nil + } + } + static func parse_updateContactLink(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.ContactLink? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ContactLink + } + var _3: Api.ContactLink? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.ContactLink + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateContactLink(userId: _1!, myLink: _2!, foreignLink: _3!) + } + else { + return nil + } + } + static func parse_updateNewEncryptedMessage(_ reader: BufferReader) -> Update? { + var _1: Api.EncryptedMessage? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.EncryptedMessage + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateNewEncryptedMessage(message: _1!, qts: _2!) + } + else { + return nil + } + } + static func parse_updateEncryptedChatTyping(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateEncryptedChatTyping(chatId: _1!) + } + else { + return nil + } + } + static func parse_updateEncryption(_ reader: BufferReader) -> Update? { + var _1: Api.EncryptedChat? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.EncryptedChat + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateEncryption(chat: _1!, date: _2!) + } + else { + return nil + } + } + static func parse_updateEncryptedMessagesRead(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateEncryptedMessagesRead(chatId: _1!, maxDate: _2!, date: _3!) + } + else { + return nil + } + } + static func parse_updateChatParticipantAdd(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.Update.updateChatParticipantAdd(chatId: _1!, userId: _2!, inviterId: _3!, date: _4!, version: _5!) + } + else { + return nil + } + } + static func parse_updateChatParticipantDelete(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChatParticipantDelete(chatId: _1!, userId: _2!, version: _3!) + } + else { + return nil + } + } + static func parse_updateDcOptions(_ reader: BufferReader) -> Update? { + var _1: [Api.DcOption]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DcOption.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateDcOptions(dcOptions: _1!) + } + else { + return nil + } + } + static func parse_updateUserBlocked(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Bool? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateUserBlocked(userId: _1!, blocked: _2!) + } + else { + return nil + } + } + static func parse_updateNotifySettings(_ reader: BufferReader) -> Update? { + var _1: Api.NotifyPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.NotifyPeer + } + var _2: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateNotifySettings(peer: _1!, notifySettings: _2!) + } + else { + return nil + } + } + static func parse_updateServiceNotification(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() } + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: Api.MessageMedia? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.MessageMedia + } + var _6: [Api.MessageEntity]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Update.updateServiceNotification(flags: _1!, inboxDate: _2, type: _3!, message: _4!, media: _5!, entities: _6!) + } + else { + return nil + } + } + static func parse_updatePrivacy(_ reader: BufferReader) -> Update? { + var _1: Api.PrivacyKey? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.PrivacyKey + } + var _2: [Api.PrivacyRule]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updatePrivacy(key: _1!, rules: _2!) + } + else { + return nil + } + } + static func parse_updateUserPhone(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateUserPhone(userId: _1!, phone: _2!) + } + else { + return nil + } + } + static func parse_updateReadHistoryOutbox(_ reader: BufferReader) -> Update? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateReadHistoryOutbox(peer: _1!, maxId: _2!, pts: _3!, ptsCount: _4!) + } + else { + return nil + } + } + static func parse_updateWebPage(_ reader: BufferReader) -> Update? { + var _1: Api.WebPage? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.WebPage + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateWebPage(webpage: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateReadMessagesContents(_ reader: BufferReader) -> Update? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateReadMessagesContents(messages: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateChannelTooLong(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChannelTooLong(flags: _1!, channelId: _2!, pts: _3) + } + else { + return nil + } + } + static func parse_updateChannel(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateChannel(channelId: _1!) + } + else { + return nil + } + } + static func parse_updateNewChannelMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateNewChannelMessage(message: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateDeleteChannelMessages(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Int32]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateDeleteChannelMessages(channelId: _1!, messages: _2!, pts: _3!, ptsCount: _4!) + } + else { + return nil + } + } + static func parse_updateChannelMessageViews(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChannelMessageViews(channelId: _1!, id: _2!, views: _3!) + } + else { + return nil + } + } + static func parse_updateChatParticipantAdmin(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.Bool? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Bool + } + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateChatParticipantAdmin(chatId: _1!, userId: _2!, isAdmin: _3!, version: _4!) + } + else { + return nil + } + } + static func parse_updateNewStickerSet(_ reader: BufferReader) -> Update? { + var _1: Api.messages.StickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.messages.StickerSet + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateNewStickerSet(stickerset: _1!) + } + else { + return nil + } + } + static func parse_updateStickerSetsOrder(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Int64]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateStickerSetsOrder(flags: _1!, order: _2!) + } + else { + return nil + } + } + static func parse_updateStickerSets(_ reader: BufferReader) -> Update? { + return Api.Update.updateStickerSets + } + static func parse_updateSavedGifs(_ reader: BufferReader) -> Update? { + return Api.Update.updateSavedGifs + } + static func parse_updateBotInlineQuery(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Api.GeoPoint? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } } + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Update.updateBotInlineQuery(flags: _1!, queryId: _2!, userId: _3!, query: _4!, geo: _5, offset: _6!) + } + else { + return nil + } + } + static func parse_updateBotInlineSend(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Api.GeoPoint? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } } + var _5: String? + _5 = parseString(reader) + var _6: Api.InputBotInlineMessageID? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessageID + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Update.updateBotInlineSend(flags: _1!, userId: _2!, query: _3!, geo: _4, id: _5!, msgId: _6) + } + else { + return nil + } + } + static func parse_updateEditChannelMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateEditChannelMessage(message: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateChannelPinnedMessage(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateChannelPinnedMessage(channelId: _1!, id: _2!) + } + else { + return nil + } + } + static func parse_updateBotCallbackQuery(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Api.Peer? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _5: Int32? + _5 = reader.readInt32() + var _6: Int64? + _6 = reader.readInt64() + var _7: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_7 = parseBytes(reader) } + var _8: String? + if Int(_1!) & Int(1 << 1) != 0 {_8 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 1) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.Update.updateBotCallbackQuery(flags: _1!, queryId: _2!, userId: _3!, peer: _4!, msgId: _5!, chatInstance: _6!, data: _7, gameShortName: _8) + } + else { + return nil + } + } + static func parse_updateEditMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateEditMessage(message: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateInlineBotCallbackQuery(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Api.InputBotInlineMessageID? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessageID + } + var _5: Int64? + _5 = reader.readInt64() + var _6: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_6 = parseBytes(reader) } + var _7: String? + if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.Update.updateInlineBotCallbackQuery(flags: _1!, queryId: _2!, userId: _3!, msgId: _4!, chatInstance: _5!, data: _6, gameShortName: _7) + } + else { + return nil + } + } + static func parse_updateReadChannelOutbox(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateReadChannelOutbox(channelId: _1!, maxId: _2!) + } + else { + return nil + } + } + static func parse_updateDraftMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Api.DraftMessage? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DraftMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateDraftMessage(peer: _1!, draft: _2!) + } + else { + return nil + } + } + static func parse_updateReadFeaturedStickers(_ reader: BufferReader) -> Update? { + return Api.Update.updateReadFeaturedStickers + } + static func parse_updateRecentStickers(_ reader: BufferReader) -> Update? { + return Api.Update.updateRecentStickers + } + static func parse_updateConfig(_ reader: BufferReader) -> Update? { + return Api.Update.updateConfig + } + static func parse_updatePtsChanged(_ reader: BufferReader) -> Update? { + return Api.Update.updatePtsChanged + } + static func parse_updateChannelWebPage(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.WebPage? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.WebPage + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateChannelWebPage(channelId: _1!, webpage: _2!, pts: _3!, ptsCount: _4!) + } + else { + return nil + } + } + static func parse_updateBotWebhookJSON(_ reader: BufferReader) -> Update? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateBotWebhookJSON(data: _1!) + } + else { + return nil + } + } + static func parse_updateBotWebhookJSONQuery(_ reader: BufferReader) -> Update? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Api.DataJSON? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateBotWebhookJSONQuery(queryId: _1!, data: _2!, timeout: _3!) + } + else { + return nil + } + } + static func parse_updateBotShippingQuery(_ reader: BufferReader) -> Update? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Api.PostAddress? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.PostAddress + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateBotShippingQuery(queryId: _1!, userId: _2!, payload: _3!, shippingAddress: _4!) + } + else { + return nil + } + } + static func parse_updateBotPrecheckoutQuery(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + var _6: String? + if Int(_1!) & Int(1 << 1) != 0 {_6 = parseString(reader) } + var _7: String? + _7 = parseString(reader) + var _8: Int64? + _8 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.Update.updateBotPrecheckoutQuery(flags: _1!, queryId: _2!, userId: _3!, payload: _4!, info: _5, shippingOptionId: _6, currency: _7!, totalAmount: _8!) + } + else { + return nil + } + } + static func parse_updatePhoneCall(_ reader: BufferReader) -> Update? { + var _1: Api.PhoneCall? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.PhoneCall + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updatePhoneCall(phoneCall: _1!) + } + else { + return nil + } + } + static func parse_updateLangPack(_ reader: BufferReader) -> Update? { + var _1: Api.LangPackDifference? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateLangPack(difference: _1!) + } + else { + return nil + } + } + static func parse_updateFavedStickers(_ reader: BufferReader) -> Update? { + return Api.Update.updateFavedStickers + } + static func parse_updateChannelReadMessagesContents(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Int32]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateChannelReadMessagesContents(channelId: _1!, messages: _2!) + } + else { + return nil + } + } + static func parse_updateContactsReset(_ reader: BufferReader) -> Update? { + return Api.Update.updateContactsReset + } + static func parse_updateChannelAvailableMessages(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateChannelAvailableMessages(channelId: _1!, availableMinId: _2!) + } + else { + return nil + } + } + static func parse_updateDialogUnreadMark(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.DialogPeer? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DialogPeer + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateDialogUnreadMark(flags: _1!, peer: _2!) + } + else { + return nil + } + } + static func parse_updateLangPackTooLong(_ reader: BufferReader) -> Update? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateLangPackTooLong(langCode: _1!) + } + else { + return nil + } + } + static func parse_updateUserPinnedMessage(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateUserPinnedMessage(userId: _1!, id: _2!) + } + else { + return nil + } + } + static func parse_updateMessagePoll(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.Poll? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Poll + } } + var _4: Api.PollResults? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.PollResults + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Update.updateMessagePoll(flags: _1!, pollId: _2!, poll: _3, results: _4!) + } + else { + return nil + } + } + static func parse_updateChatDefaultBannedRights(_ reader: BufferReader) -> Update? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Api.ChatBannedRights? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChatDefaultBannedRights(peer: _1!, defaultBannedRights: _2!, version: _3!) + } + else { + return nil + } + } + static func parse_updateChatPinnedMessage(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChatPinnedMessage(chatId: _1!, id: _2!, version: _3!) + } + else { + return nil + } + } + static func parse_updateFolderPeers(_ reader: BufferReader) -> Update? { + var _1: [Api.FolderPeer]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.FolderPeer.self) + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateFolderPeers(folderPeers: _1!, pts: _2!, ptsCount: _3!) + } + else { + return nil + } + } + static func parse_updateDialogPinned(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() } + var _3: Api.DialogPeer? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.DialogPeer + } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateDialogPinned(flags: _1!, folderId: _2, peer: _3!) + } + else { + return nil + } + } + static func parse_updatePinnedDialogs(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() } + var _3: [Api.DialogPeer]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DialogPeer.self) + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updatePinnedDialogs(flags: _1!, folderId: _2, order: _3) + } + else { + return nil + } + } + static func parse_updateReadChannelInbox(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Update.updateReadChannelInbox(flags: _1!, folderId: _2, channelId: _3!, maxId: _4!, stillUnreadCount: _5!, pts: _6!) + } + else { + return nil + } + } + static func parse_updateReadHistoryInbox(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Api.Peer? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.Update.updateReadHistoryInbox(flags: _1!, folderId: _2, peer: _3!, maxId: _4!, stillUnreadCount: _5!, pts: _6!, ptsCount: _7!) + } + else { + return nil + } + } + static func parse_updatePeerSettings(_ reader: BufferReader) -> Update? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Api.PeerSettings? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PeerSettings + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updatePeerSettings(peer: _1!, settings: _2!) + } + else { + return nil + } + } + static func parse_updateContactLocated(_ reader: BufferReader) -> Update? { + var _1: [Api.ContactLocated]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ContactLocated.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateContactLocated(contacts: _1!) + } + else { + return nil + } + } + + } + enum PopularContact: TypeConstructorDescription { + case popularContact(clientId: Int64, importers: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .popularContact(let clientId, let importers): + if boxed { + buffer.appendInt32(1558266229) + } + serializeInt64(clientId, buffer: buffer, boxed: false) + serializeInt32(importers, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .popularContact(let clientId, let importers): + return ("popularContact", [("clientId", clientId), ("importers", importers)]) + } + } + + static func parse_popularContact(_ reader: BufferReader) -> PopularContact? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PopularContact.popularContact(clientId: _1!, importers: _2!) + } + else { + return nil + } + } + + } + enum FolderPeer: TypeConstructorDescription { + case folderPeer(peer: Api.Peer, folderId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .folderPeer(let peer, let folderId): + if boxed { + buffer.appendInt32(-373643672) + } + peer.serialize(buffer, true) + serializeInt32(folderId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .folderPeer(let peer, let folderId): + return ("folderPeer", [("peer", peer), ("folderId", folderId)]) + } + } + + static func parse_folderPeer(_ reader: BufferReader) -> FolderPeer? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.FolderPeer.folderPeer(peer: _1!, folderId: _2!) + } + else { + return nil + } + } + + } + enum ChannelParticipant: TypeConstructorDescription { + case channelParticipant(userId: Int32, date: Int32) + case channelParticipantSelf(userId: Int32, inviterId: Int32, date: Int32) + case channelParticipantCreator(userId: Int32) + case channelParticipantBanned(flags: Int32, userId: Int32, kickedBy: Int32, date: Int32, bannedRights: Api.ChatBannedRights) + case channelParticipantAdmin(flags: Int32, userId: Int32, inviterId: Int32?, promotedBy: Int32, date: Int32, adminRights: Api.ChatAdminRights) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelParticipant(let userId, let date): + if boxed { + buffer.appendInt32(367766557) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .channelParticipantSelf(let userId, let inviterId, let date): + if boxed { + buffer.appendInt32(-1557620115) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(inviterId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .channelParticipantCreator(let userId): + if boxed { + buffer.appendInt32(-471670279) + } + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): + if boxed { + buffer.appendInt32(470789295) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(kickedBy, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + bannedRights.serialize(buffer, true) + break + case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights): + if boxed { + buffer.appendInt32(1571450403) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(inviterId!, buffer: buffer, boxed: false)} + serializeInt32(promotedBy, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + adminRights.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelParticipant(let userId, let date): + return ("channelParticipant", [("userId", userId), ("date", date)]) + case .channelParticipantSelf(let userId, let inviterId, let date): + return ("channelParticipantSelf", [("userId", userId), ("inviterId", inviterId), ("date", date)]) + case .channelParticipantCreator(let userId): + return ("channelParticipantCreator", [("userId", userId)]) + case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): + return ("channelParticipantBanned", [("flags", flags), ("userId", userId), ("kickedBy", kickedBy), ("date", date), ("bannedRights", bannedRights)]) + case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights): + return ("channelParticipantAdmin", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("promotedBy", promotedBy), ("date", date), ("adminRights", adminRights)]) + } + } + + static func parse_channelParticipant(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelParticipant.channelParticipant(userId: _1!, date: _2!) + } + else { + return nil + } + } + static func parse_channelParticipantSelf(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChannelParticipant.channelParticipantSelf(userId: _1!, inviterId: _2!, date: _3!) + } + else { + return nil + } + } + static func parse_channelParticipantCreator(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ChannelParticipant.channelParticipantCreator(userId: _1!) + } + else { + return nil + } + } + static func parse_channelParticipantBanned(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Api.ChatBannedRights? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.ChannelParticipant.channelParticipantBanned(flags: _1!, userId: _2!, kickedBy: _3!, date: _4!, bannedRights: _5!) + } + else { + return nil + } + } + static func parse_channelParticipantAdmin(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Api.ChatAdminRights? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.ChannelParticipant.channelParticipantAdmin(flags: _1!, userId: _2!, inviterId: _3, promotedBy: _4!, date: _5!, adminRights: _6!) + } + else { + return nil + } + } + + } + enum InputDialogPeer: TypeConstructorDescription { + case inputDialogPeer(peer: Api.InputPeer) + case inputDialogPeerFolder(folderId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputDialogPeer(let peer): + if boxed { + buffer.appendInt32(-55902537) + } + peer.serialize(buffer, true) + break + case .inputDialogPeerFolder(let folderId): + if boxed { + buffer.appendInt32(1684014375) + } + serializeInt32(folderId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputDialogPeer(let peer): + return ("inputDialogPeer", [("peer", peer)]) + case .inputDialogPeerFolder(let folderId): + return ("inputDialogPeerFolder", [("folderId", folderId)]) + } + } + + static func parse_inputDialogPeer(_ reader: BufferReader) -> InputDialogPeer? { + var _1: Api.InputPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + let _c1 = _1 != nil + if _c1 { + return Api.InputDialogPeer.inputDialogPeer(peer: _1!) + } + else { + return nil + } + } + static func parse_inputDialogPeerFolder(_ reader: BufferReader) -> InputDialogPeer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.InputDialogPeer.inputDialogPeerFolder(folderId: _1!) + } + else { + return nil + } + } + + } + enum Error: TypeConstructorDescription { + case error(code: Int32, text: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .error(let code, let text): + if boxed { + buffer.appendInt32(-994444869) + } + serializeInt32(code, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .error(let code, let text): + return ("error", [("code", code), ("text", text)]) + } + } + + static func parse_error(_ reader: BufferReader) -> Error? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Error.error(code: _1!, text: _2!) + } + else { + return nil + } + } + + } + enum ContactLocated: TypeConstructorDescription { + case contactLocated(userId: Int32, expires: Int32, distance: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contactLocated(let userId, let expires, let distance): + if boxed { + buffer.appendInt32(-1150339286) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(expires, buffer: buffer, boxed: false) + serializeInt32(distance, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contactLocated(let userId, let expires, let distance): + return ("contactLocated", [("userId", userId), ("expires", expires), ("distance", distance)]) + } + } + + static func parse_contactLocated(_ reader: BufferReader) -> ContactLocated? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ContactLocated.contactLocated(userId: _1!, expires: _2!, distance: _3!) + } + else { + return nil + } + } + + } + enum KeyboardButton: TypeConstructorDescription { + case keyboardButton(text: String) + case keyboardButtonUrl(text: String, url: String) + case keyboardButtonCallback(text: String, data: Buffer) + case keyboardButtonRequestPhone(text: String) + case keyboardButtonRequestGeoLocation(text: String) + case keyboardButtonSwitchInline(flags: Int32, text: String, query: String) + case keyboardButtonGame(text: String) + case keyboardButtonBuy(text: String) + case keyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, buttonId: Int32) + case inputKeyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, bot: Api.InputUser) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .keyboardButton(let text): + if boxed { + buffer.appendInt32(-1560655744) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .keyboardButtonUrl(let text, let url): + if boxed { + buffer.appendInt32(629866245) + } + serializeString(text, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + break + case .keyboardButtonCallback(let text, let data): + if boxed { + buffer.appendInt32(1748655686) + } + serializeString(text, buffer: buffer, boxed: false) + serializeBytes(data, buffer: buffer, boxed: false) + break + case .keyboardButtonRequestPhone(let text): + if boxed { + buffer.appendInt32(-1318425559) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .keyboardButtonRequestGeoLocation(let text): + if boxed { + buffer.appendInt32(-59151553) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .keyboardButtonSwitchInline(let flags, let text, let query): + if boxed { + buffer.appendInt32(90744648) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + serializeString(query, buffer: buffer, boxed: false) + break + case .keyboardButtonGame(let text): + if boxed { + buffer.appendInt32(1358175439) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .keyboardButtonBuy(let text): + if boxed { + buffer.appendInt32(-1344716869) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId): + if boxed { + buffer.appendInt32(280464681) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)} + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(buttonId, buffer: buffer, boxed: false) + break + case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot): + if boxed { + buffer.appendInt32(-802258988) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)} + serializeString(url, buffer: buffer, boxed: false) + bot.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .keyboardButton(let text): + return ("keyboardButton", [("text", text)]) + case .keyboardButtonUrl(let text, let url): + return ("keyboardButtonUrl", [("text", text), ("url", url)]) + case .keyboardButtonCallback(let text, let data): + return ("keyboardButtonCallback", [("text", text), ("data", data)]) + case .keyboardButtonRequestPhone(let text): + return ("keyboardButtonRequestPhone", [("text", text)]) + case .keyboardButtonRequestGeoLocation(let text): + return ("keyboardButtonRequestGeoLocation", [("text", text)]) + case .keyboardButtonSwitchInline(let flags, let text, let query): + return ("keyboardButtonSwitchInline", [("flags", flags), ("text", text), ("query", query)]) + case .keyboardButtonGame(let text): + return ("keyboardButtonGame", [("text", text)]) + case .keyboardButtonBuy(let text): + return ("keyboardButtonBuy", [("text", text)]) + case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId): + return ("keyboardButtonUrlAuth", [("flags", flags), ("text", text), ("fwdText", fwdText), ("url", url), ("buttonId", buttonId)]) + case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot): + return ("inputKeyboardButtonUrlAuth", [("flags", flags), ("text", text), ("fwdText", fwdText), ("url", url), ("bot", bot)]) + } + } + + static func parse_keyboardButton(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButton.keyboardButton(text: _1!) + } + else { + return nil + } + } + static func parse_keyboardButtonUrl(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.KeyboardButton.keyboardButtonUrl(text: _1!, url: _2!) + } + else { + return nil + } + } + static func parse_keyboardButtonCallback(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.KeyboardButton.keyboardButtonCallback(text: _1!, data: _2!) + } + else { + return nil + } + } + static func parse_keyboardButtonRequestPhone(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButton.keyboardButtonRequestPhone(text: _1!) + } + else { + return nil + } + } + static func parse_keyboardButtonRequestGeoLocation(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButton.keyboardButtonRequestGeoLocation(text: _1!) + } + else { + return nil + } + } + static func parse_keyboardButtonSwitchInline(_ reader: BufferReader) -> KeyboardButton? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.KeyboardButton.keyboardButtonSwitchInline(flags: _1!, text: _2!, query: _3!) + } + else { + return nil + } + } + static func parse_keyboardButtonGame(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButton.keyboardButtonGame(text: _1!) + } + else { + return nil + } + } + static func parse_keyboardButtonBuy(_ reader: BufferReader) -> KeyboardButton? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButton.keyboardButtonBuy(text: _1!) + } + else { + return nil + } + } + static func parse_keyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.KeyboardButton.keyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, buttonId: _5!) + } + else { + return nil + } + } + static func parse_inputKeyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: String? + _4 = parseString(reader) + var _5: Api.InputUser? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.InputUser + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.KeyboardButton.inputKeyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, bot: _5!) + } + else { + return nil + } + } + + } + enum ContactStatus: TypeConstructorDescription { + case contactStatus(userId: Int32, status: Api.UserStatus) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contactStatus(let userId, let status): + if boxed { + buffer.appendInt32(-748155807) + } + serializeInt32(userId, buffer: buffer, boxed: false) + status.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contactStatus(let userId, let status): + return ("contactStatus", [("userId", userId), ("status", status)]) + } + } + + static func parse_contactStatus(_ reader: BufferReader) -> ContactStatus? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.UserStatus? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.UserStatus + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ContactStatus.contactStatus(userId: _1!, status: _2!) + } + else { + return nil + } + } + + } + enum SecureFile: TypeConstructorDescription { + case secureFileEmpty + case secureFile(id: Int64, accessHash: Int64, size: Int32, dcId: Int32, date: Int32, fileHash: Buffer, secret: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureFileEmpty: + if boxed { + buffer.appendInt32(1679398724) + } + + break + case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret): + if boxed { + buffer.appendInt32(-534283678) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeBytes(secret, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureFileEmpty: + return ("secureFileEmpty", []) + case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret): + return ("secureFile", [("id", id), ("accessHash", accessHash), ("size", size), ("dcId", dcId), ("date", date), ("fileHash", fileHash), ("secret", secret)]) + } + } + + static func parse_secureFileEmpty(_ reader: BufferReader) -> SecureFile? { + return Api.SecureFile.secureFileEmpty + } + static func parse_secureFile(_ reader: BufferReader) -> SecureFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Buffer? + _6 = parseBytes(reader) + var _7: Buffer? + _7 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.SecureFile.secureFile(id: _1!, accessHash: _2!, size: _3!, dcId: _4!, date: _5!, fileHash: _6!, secret: _7!) + } + else { + return nil + } + } + + } + enum PhotoSize: TypeConstructorDescription { + case photoSizeEmpty(type: String) + case photoSize(type: String, location: Api.FileLocation, w: Int32, h: Int32, size: Int32) + case photoCachedSize(type: String, location: Api.FileLocation, w: Int32, h: Int32, bytes: Buffer) + case photoStrippedSize(type: String, bytes: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photoSizeEmpty(let type): + if boxed { + buffer.appendInt32(236446268) + } + serializeString(type, buffer: buffer, boxed: false) + break + case .photoSize(let type, let location, let w, let h, let size): + if boxed { + buffer.appendInt32(2009052699) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + break + case .photoCachedSize(let type, let location, let w, let h, let bytes): + if boxed { + buffer.appendInt32(-374917894) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + case .photoStrippedSize(let type, let bytes): + if boxed { + buffer.appendInt32(-525288402) + } + serializeString(type, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .photoSizeEmpty(let type): + return ("photoSizeEmpty", [("type", type)]) + case .photoSize(let type, let location, let w, let h, let size): + return ("photoSize", [("type", type), ("location", location), ("w", w), ("h", h), ("size", size)]) + case .photoCachedSize(let type, let location, let w, let h, let bytes): + return ("photoCachedSize", [("type", type), ("location", location), ("w", w), ("h", h), ("bytes", bytes)]) + case .photoStrippedSize(let type, let bytes): + return ("photoStrippedSize", [("type", type), ("bytes", bytes)]) + } + } + + static func parse_photoSizeEmpty(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.PhotoSize.photoSizeEmpty(type: _1!) + } + else { + return nil + } + } + static func parse_photoSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: Api.FileLocation? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PhotoSize.photoSize(type: _1!, location: _2!, w: _3!, h: _4!, size: _5!) + } + else { + return nil + } + } + static func parse_photoCachedSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: Api.FileLocation? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PhotoSize.photoCachedSize(type: _1!, location: _2!, w: _3!, h: _4!, bytes: _5!) + } + else { + return nil + } + } + static func parse_photoStrippedSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PhotoSize.photoStrippedSize(type: _1!, bytes: _2!) + } + else { + return nil + } + } + + } + enum InlineBotSwitchPM: TypeConstructorDescription { + case inlineBotSwitchPM(text: String, startParam: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + if boxed { + buffer.appendInt32(1008755359) + } + serializeString(text, buffer: buffer, boxed: false) + serializeString(startParam, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + return ("inlineBotSwitchPM", [("text", text), ("startParam", startParam)]) + } + } + + static func parse_inlineBotSwitchPM(_ reader: BufferReader) -> InlineBotSwitchPM? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InlineBotSwitchPM.inlineBotSwitchPM(text: _1!, startParam: _2!) + } + else { + return nil + } + } + + } + enum FileLocation: TypeConstructorDescription { + case fileLocationToBeDeprecated(volumeId: Int64, localId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileLocationToBeDeprecated(let volumeId, let localId): + if boxed { + buffer.appendInt32(-1132476723) + } + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .fileLocationToBeDeprecated(let volumeId, let localId): + return ("fileLocationToBeDeprecated", [("volumeId", volumeId), ("localId", localId)]) + } + } + + static func parse_fileLocationToBeDeprecated(_ reader: BufferReader) -> FileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.FileLocation.fileLocationToBeDeprecated(volumeId: _1!, localId: _2!) + } + else { + return nil + } + } + + } + enum Poll: TypeConstructorDescription { + case poll(id: Int64, flags: Int32, question: String, answers: [Api.PollAnswer]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .poll(let id, let flags, let question, let answers): + if boxed { + buffer.appendInt32(-716006138) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(question, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(answers.count)) + for item in answers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .poll(let id, let flags, let question, let answers): + return ("poll", [("id", id), ("flags", flags), ("question", question), ("answers", answers)]) + } + } + + static func parse_poll(_ reader: BufferReader) -> Poll? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: [Api.PollAnswer]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PollAnswer.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.Poll.poll(id: _1!, flags: _2!, question: _3!, answers: _4!) + } + else { + return nil + } + } + + } + enum InputNotifyPeer: TypeConstructorDescription { + case inputNotifyUsers + case inputNotifyChats + case inputNotifyBroadcasts + case inputNotifyPeer(peer: Api.InputPeer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputNotifyUsers: + if boxed { + buffer.appendInt32(423314455) + } + + break + case .inputNotifyChats: + if boxed { + buffer.appendInt32(1251338318) + } + + break + case .inputNotifyBroadcasts: + if boxed { + buffer.appendInt32(-1311015810) + } + + break + case .inputNotifyPeer(let peer): + if boxed { + buffer.appendInt32(-1195615476) + } + peer.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputNotifyUsers: + return ("inputNotifyUsers", []) + case .inputNotifyChats: + return ("inputNotifyChats", []) + case .inputNotifyBroadcasts: + return ("inputNotifyBroadcasts", []) + case .inputNotifyPeer(let peer): + return ("inputNotifyPeer", [("peer", peer)]) + } + } + + static func parse_inputNotifyUsers(_ reader: BufferReader) -> InputNotifyPeer? { + return Api.InputNotifyPeer.inputNotifyUsers + } + static func parse_inputNotifyChats(_ reader: BufferReader) -> InputNotifyPeer? { + return Api.InputNotifyPeer.inputNotifyChats + } + static func parse_inputNotifyBroadcasts(_ reader: BufferReader) -> InputNotifyPeer? { + return Api.InputNotifyPeer.inputNotifyBroadcasts + } + static func parse_inputNotifyPeer(_ reader: BufferReader) -> InputNotifyPeer? { + var _1: Api.InputPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + let _c1 = _1 != nil + if _c1 { + return Api.InputNotifyPeer.inputNotifyPeer(peer: _1!) + } + else { + return nil + } + } + + } + enum EncryptedMessage: TypeConstructorDescription { + case encryptedMessage(randomId: Int64, chatId: Int32, date: Int32, bytes: Buffer, file: Api.EncryptedFile) + case encryptedMessageService(randomId: Int64, chatId: Int32, date: Int32, bytes: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .encryptedMessage(let randomId, let chatId, let date, let bytes, let file): + if boxed { + buffer.appendInt32(-317144808) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + file.serialize(buffer, true) + break + case .encryptedMessageService(let randomId, let chatId, let date, let bytes): + if boxed { + buffer.appendInt32(594758406) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .encryptedMessage(let randomId, let chatId, let date, let bytes, let file): + return ("encryptedMessage", [("randomId", randomId), ("chatId", chatId), ("date", date), ("bytes", bytes), ("file", file)]) + case .encryptedMessageService(let randomId, let chatId, let date, let bytes): + return ("encryptedMessageService", [("randomId", randomId), ("chatId", chatId), ("date", date), ("bytes", bytes)]) + } + } + + static func parse_encryptedMessage(_ reader: BufferReader) -> EncryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Api.EncryptedFile? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.EncryptedFile + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.EncryptedMessage.encryptedMessage(randomId: _1!, chatId: _2!, date: _3!, bytes: _4!, file: _5!) + } + else { + return nil + } + } + static func parse_encryptedMessageService(_ reader: BufferReader) -> EncryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.EncryptedMessage.encryptedMessageService(randomId: _1!, chatId: _2!, date: _3!, bytes: _4!) + } + else { + return nil + } + } + + } + enum ChannelParticipantsFilter: TypeConstructorDescription { + case channelParticipantsRecent + case channelParticipantsAdmins + case channelParticipantsBots + case channelParticipantsBanned(q: String) + case channelParticipantsSearch(q: String) + case channelParticipantsKicked(q: String) + case channelParticipantsContacts(q: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelParticipantsRecent: + if boxed { + buffer.appendInt32(-566281095) + } + + break + case .channelParticipantsAdmins: + if boxed { + buffer.appendInt32(-1268741783) + } + + break + case .channelParticipantsBots: + if boxed { + buffer.appendInt32(-1328445861) + } + + break + case .channelParticipantsBanned(let q): + if boxed { + buffer.appendInt32(338142689) + } + serializeString(q, buffer: buffer, boxed: false) + break + case .channelParticipantsSearch(let q): + if boxed { + buffer.appendInt32(106343499) + } + serializeString(q, buffer: buffer, boxed: false) + break + case .channelParticipantsKicked(let q): + if boxed { + buffer.appendInt32(-1548400251) + } + serializeString(q, buffer: buffer, boxed: false) + break + case .channelParticipantsContacts(let q): + if boxed { + buffer.appendInt32(-1150621555) + } + serializeString(q, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelParticipantsRecent: + return ("channelParticipantsRecent", []) + case .channelParticipantsAdmins: + return ("channelParticipantsAdmins", []) + case .channelParticipantsBots: + return ("channelParticipantsBots", []) + case .channelParticipantsBanned(let q): + return ("channelParticipantsBanned", [("q", q)]) + case .channelParticipantsSearch(let q): + return ("channelParticipantsSearch", [("q", q)]) + case .channelParticipantsKicked(let q): + return ("channelParticipantsKicked", [("q", q)]) + case .channelParticipantsContacts(let q): + return ("channelParticipantsContacts", [("q", q)]) + } + } + + static func parse_channelParticipantsRecent(_ reader: BufferReader) -> ChannelParticipantsFilter? { + return Api.ChannelParticipantsFilter.channelParticipantsRecent + } + static func parse_channelParticipantsAdmins(_ reader: BufferReader) -> ChannelParticipantsFilter? { + return Api.ChannelParticipantsFilter.channelParticipantsAdmins + } + static func parse_channelParticipantsBots(_ reader: BufferReader) -> ChannelParticipantsFilter? { + return Api.ChannelParticipantsFilter.channelParticipantsBots + } + static func parse_channelParticipantsBanned(_ reader: BufferReader) -> ChannelParticipantsFilter? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ChannelParticipantsFilter.channelParticipantsBanned(q: _1!) + } + else { + return nil + } + } + static func parse_channelParticipantsSearch(_ reader: BufferReader) -> ChannelParticipantsFilter? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ChannelParticipantsFilter.channelParticipantsSearch(q: _1!) + } + else { + return nil + } + } + static func parse_channelParticipantsKicked(_ reader: BufferReader) -> ChannelParticipantsFilter? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ChannelParticipantsFilter.channelParticipantsKicked(q: _1!) + } + else { + return nil + } + } + static func parse_channelParticipantsContacts(_ reader: BufferReader) -> ChannelParticipantsFilter? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ChannelParticipantsFilter.channelParticipantsContacts(q: _1!) + } + else { + return nil + } + } + + } + enum WebPage: TypeConstructorDescription { + case webPageEmpty(id: Int64) + case webPagePending(id: Int64, date: Int32) + case webPage(flags: Int32, id: Int64, url: String, displayUrl: String, hash: Int32, type: String?, siteName: String?, title: String?, description: String?, photo: Api.Photo?, embedUrl: String?, embedType: String?, embedWidth: Int32?, embedHeight: Int32?, duration: Int32?, author: String?, document: Api.Document?, cachedPage: Api.Page?) + case webPageNotModified + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .webPageEmpty(let id): + if boxed { + buffer.appendInt32(-350980120) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + case .webPagePending(let id, let date): + if boxed { + buffer.appendInt32(-981018084) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let cachedPage): + if boxed { + buffer.appendInt32(1594340540) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + serializeString(displayUrl, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(type!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(siteName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {serializeString(embedUrl!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeString(embedType!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 6) != 0 {serializeInt32(embedWidth!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 6) != 0 {serializeInt32(embedHeight!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 7) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 8) != 0 {serializeString(author!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 9) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 10) != 0 {cachedPage!.serialize(buffer, true)} + break + case .webPageNotModified: + if boxed { + buffer.appendInt32(-2054908813) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .webPageEmpty(let id): + return ("webPageEmpty", [("id", id)]) + case .webPagePending(let id, let date): + return ("webPagePending", [("id", id), ("date", date)]) + case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let cachedPage): + return ("webPage", [("flags", flags), ("id", id), ("url", url), ("displayUrl", displayUrl), ("hash", hash), ("type", type), ("siteName", siteName), ("title", title), ("description", description), ("photo", photo), ("embedUrl", embedUrl), ("embedType", embedType), ("embedWidth", embedWidth), ("embedHeight", embedHeight), ("duration", duration), ("author", author), ("document", document), ("cachedPage", cachedPage)]) + case .webPageNotModified: + return ("webPageNotModified", []) + } + } + + static func parse_webPageEmpty(_ reader: BufferReader) -> WebPage? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.WebPage.webPageEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_webPagePending(_ reader: BufferReader) -> WebPage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.WebPage.webPagePending(id: _1!, date: _2!) + } + else { + return nil + } + } + static func parse_webPage(_ reader: BufferReader) -> WebPage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: String? + if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) } + var _8: String? + if Int(_1!) & Int(1 << 2) != 0 {_8 = parseString(reader) } + var _9: String? + if Int(_1!) & Int(1 << 3) != 0 {_9 = parseString(reader) } + var _10: Api.Photo? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _11: String? + if Int(_1!) & Int(1 << 5) != 0 {_11 = parseString(reader) } + var _12: String? + if Int(_1!) & Int(1 << 5) != 0 {_12 = parseString(reader) } + var _13: Int32? + if Int(_1!) & Int(1 << 6) != 0 {_13 = reader.readInt32() } + var _14: Int32? + if Int(_1!) & Int(1 << 6) != 0 {_14 = reader.readInt32() } + var _15: Int32? + if Int(_1!) & Int(1 << 7) != 0 {_15 = reader.readInt32() } + var _16: String? + if Int(_1!) & Int(1 << 8) != 0 {_16 = parseString(reader) } + var _17: Api.Document? + if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() { + _17 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _18: Api.Page? + if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() { + _18 = Api.parse(reader, signature: signature) as? Api.Page + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 4) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 5) == 0) || _11 != nil + let _c12 = (Int(_1!) & Int(1 << 5) == 0) || _12 != nil + let _c13 = (Int(_1!) & Int(1 << 6) == 0) || _13 != nil + let _c14 = (Int(_1!) & Int(1 << 6) == 0) || _14 != nil + let _c15 = (Int(_1!) & Int(1 << 7) == 0) || _15 != nil + let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil + let _c17 = (Int(_1!) & Int(1 << 9) == 0) || _17 != nil + let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 { + return Api.WebPage.webPage(flags: _1!, id: _2!, url: _3!, displayUrl: _4!, hash: _5!, type: _6, siteName: _7, title: _8, description: _9, photo: _10, embedUrl: _11, embedType: _12, embedWidth: _13, embedHeight: _14, duration: _15, author: _16, document: _17, cachedPage: _18) + } + else { + return nil + } + } + static func parse_webPageNotModified(_ reader: BufferReader) -> WebPage? { + return Api.WebPage.webPageNotModified + } + + } + enum InputBotInlineMessage: TypeConstructorDescription { + case inputBotInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?) + case inputBotInlineMessageMediaGeo(flags: Int32, geoPoint: Api.InputGeoPoint, replyMarkup: Api.ReplyMarkup?) + case inputBotInlineMessageGame(flags: Int32, replyMarkup: Api.ReplyMarkup?) + case inputBotInlineMessageMediaAuto(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?) + case inputBotInlineMessageMediaVenue(flags: Int32, geoPoint: Api.InputGeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?) + case inputBotInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBotInlineMessageText(let flags, let message, let entities, let replyMarkup): + if boxed { + buffer.appendInt32(1036876423) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let replyMarkup): + if boxed { + buffer.appendInt32(-190472735) + } + serializeInt32(flags, buffer: buffer, boxed: false) + geoPoint.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .inputBotInlineMessageGame(let flags, let replyMarkup): + if boxed { + buffer.appendInt32(1262639204) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .inputBotInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup): + if boxed { + buffer.appendInt32(864077702) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .inputBotInlineMessageMediaVenue(let flags, let geoPoint, let title, let address, let provider, let venueId, let venueType, let replyMarkup): + if boxed { + buffer.appendInt32(1098628881) + } + serializeInt32(flags, buffer: buffer, boxed: false) + geoPoint.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + serializeString(venueType, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .inputBotInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup): + if boxed { + buffer.appendInt32(-1494368259) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(vcard, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBotInlineMessageText(let flags, let message, let entities, let replyMarkup): + return ("inputBotInlineMessageText", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)]) + case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let replyMarkup): + return ("inputBotInlineMessageMediaGeo", [("flags", flags), ("geoPoint", geoPoint), ("replyMarkup", replyMarkup)]) + case .inputBotInlineMessageGame(let flags, let replyMarkup): + return ("inputBotInlineMessageGame", [("flags", flags), ("replyMarkup", replyMarkup)]) + case .inputBotInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup): + return ("inputBotInlineMessageMediaAuto", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)]) + case .inputBotInlineMessageMediaVenue(let flags, let geoPoint, let title, let address, let provider, let venueId, let venueType, let replyMarkup): + return ("inputBotInlineMessageMediaVenue", [("flags", flags), ("geoPoint", geoPoint), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType), ("replyMarkup", replyMarkup)]) + case .inputBotInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup): + return ("inputBotInlineMessageMediaContact", [("flags", flags), ("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("replyMarkup", replyMarkup)]) + } + } + + static func parse_inputBotInlineMessageText(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _4: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputBotInlineMessage.inputBotInlineMessageText(flags: _1!, message: _2!, entities: _3, replyMarkup: _4) + } + else { + return nil + } + } + static func parse_inputBotInlineMessageMediaGeo(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _3: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputBotInlineMessage.inputBotInlineMessageMediaGeo(flags: _1!, geoPoint: _2!, replyMarkup: _3) + } + else { + return nil + } + } + static func parse_inputBotInlineMessageGame(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil + if _c1 && _c2 { + return Api.InputBotInlineMessage.inputBotInlineMessageGame(flags: _1!, replyMarkup: _2) + } + else { + return nil + } + } + static func parse_inputBotInlineMessageMediaAuto(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _4: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputBotInlineMessage.inputBotInlineMessageMediaAuto(flags: _1!, message: _2!, entities: _3, replyMarkup: _4) + } + else { + return nil + } + } + static func parse_inputBotInlineMessageMediaVenue(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + var _7: String? + _7 = parseString(reader) + var _8: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.InputBotInlineMessage.inputBotInlineMessageMediaVenue(flags: _1!, geoPoint: _2!, title: _3!, address: _4!, provider: _5!, venueId: _6!, venueType: _7!, replyMarkup: _8) + } + else { + return nil + } + } + static func parse_inputBotInlineMessageMediaContact(_ reader: BufferReader) -> InputBotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputBotInlineMessage.inputBotInlineMessageMediaContact(flags: _1!, phoneNumber: _2!, firstName: _3!, lastName: _4!, vcard: _5!, replyMarkup: _6) + } + else { + return nil + } + } + + } + enum KeyboardButtonRow: TypeConstructorDescription { + case keyboardButtonRow(buttons: [Api.KeyboardButton]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .keyboardButtonRow(let buttons): + if boxed { + buffer.appendInt32(2002815875) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(buttons.count)) + for item in buttons { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .keyboardButtonRow(let buttons): + return ("keyboardButtonRow", [("buttons", buttons)]) + } + } + + static func parse_keyboardButtonRow(_ reader: BufferReader) -> KeyboardButtonRow? { + var _1: [Api.KeyboardButton]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.KeyboardButton.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.KeyboardButtonRow.keyboardButtonRow(buttons: _1!) + } + else { + return nil + } + } + + } + enum StickerSet: TypeConstructorDescription { + case stickerSet(flags: Int32, installedDate: Int32?, id: Int64, accessHash: Int64, title: String, shortName: String, thumb: Api.PhotoSize?, thumbDcId: Int32?, count: Int32, hash: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumb, let thumbDcId, let count, let hash): + if boxed { + buffer.appendInt32(-290164953) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(installedDate!, buffer: buffer, boxed: false)} + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(shortName, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(thumbDcId!, buffer: buffer, boxed: false)} + serializeInt32(count, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumb, let thumbDcId, let count, let hash): + return ("stickerSet", [("flags", flags), ("installedDate", installedDate), ("id", id), ("accessHash", accessHash), ("title", title), ("shortName", shortName), ("thumb", thumb), ("thumbDcId", thumbDcId), ("count", count), ("hash", hash)]) + } + } + + static func parse_stickerSet(_ reader: BufferReader) -> StickerSet? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Int64? + _3 = reader.readInt64() + var _4: Int64? + _4 = reader.readInt64() + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + var _7: Api.PhotoSize? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PhotoSize + } } + var _8: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_8 = reader.readInt32() } + var _9: Int32? + _9 = reader.readInt32() + var _10: Int32? + _10 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.StickerSet.stickerSet(flags: _1!, installedDate: _2, id: _3!, accessHash: _4!, title: _5!, shortName: _6!, thumb: _7, thumbDcId: _8, count: _9!, hash: _10!) + } + else { + return nil + } + } + + } + enum SecureSecretSettings: TypeConstructorDescription { + case secureSecretSettings(secureAlgo: Api.SecurePasswordKdfAlgo, secureSecret: Buffer, secureSecretId: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureSecretSettings(let secureAlgo, let secureSecret, let secureSecretId): + if boxed { + buffer.appendInt32(354925740) + } + secureAlgo.serialize(buffer, true) + serializeBytes(secureSecret, buffer: buffer, boxed: false) + serializeInt64(secureSecretId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureSecretSettings(let secureAlgo, let secureSecret, let secureSecretId): + return ("secureSecretSettings", [("secureAlgo", secureAlgo), ("secureSecret", secureSecret), ("secureSecretId", secureSecretId)]) + } + } + + static func parse_secureSecretSettings(_ reader: BufferReader) -> SecureSecretSettings? { + var _1: Api.SecurePasswordKdfAlgo? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecurePasswordKdfAlgo + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureSecretSettings.secureSecretSettings(secureAlgo: _1!, secureSecret: _2!, secureSecretId: _3!) + } + else { + return nil + } + } + + } + enum InputContact: TypeConstructorDescription { + case inputPhoneContact(clientId: Int64, phone: String, firstName: String, lastName: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPhoneContact(let clientId, let phone, let firstName, let lastName): + if boxed { + buffer.appendInt32(-208488460) + } + serializeInt64(clientId, buffer: buffer, boxed: false) + serializeString(phone, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPhoneContact(let clientId, let phone, let firstName, let lastName): + return ("inputPhoneContact", [("clientId", clientId), ("phone", phone), ("firstName", firstName), ("lastName", lastName)]) + } + } + + static func parse_inputPhoneContact(_ reader: BufferReader) -> InputContact? { + var _1: Int64? + _1 = reader.readInt64() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputContact.inputPhoneContact(clientId: _1!, phone: _2!, firstName: _3!, lastName: _4!) + } + else { + return nil + } + } + + } + enum TopPeerCategory: TypeConstructorDescription { + case topPeerCategoryBotsPM + case topPeerCategoryBotsInline + case topPeerCategoryCorrespondents + case topPeerCategoryGroups + case topPeerCategoryChannels + case topPeerCategoryPhoneCalls + case topPeerCategoryForwardUsers + case topPeerCategoryForwardChats + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .topPeerCategoryBotsPM: + if boxed { + buffer.appendInt32(-1419371685) + } + + break + case .topPeerCategoryBotsInline: + if boxed { + buffer.appendInt32(344356834) + } + + break + case .topPeerCategoryCorrespondents: + if boxed { + buffer.appendInt32(104314861) + } + + break + case .topPeerCategoryGroups: + if boxed { + buffer.appendInt32(-1122524854) + } + + break + case .topPeerCategoryChannels: + if boxed { + buffer.appendInt32(371037736) + } + + break + case .topPeerCategoryPhoneCalls: + if boxed { + buffer.appendInt32(511092620) + } + + break + case .topPeerCategoryForwardUsers: + if boxed { + buffer.appendInt32(-1472172887) + } + + break + case .topPeerCategoryForwardChats: + if boxed { + buffer.appendInt32(-68239120) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .topPeerCategoryBotsPM: + return ("topPeerCategoryBotsPM", []) + case .topPeerCategoryBotsInline: + return ("topPeerCategoryBotsInline", []) + case .topPeerCategoryCorrespondents: + return ("topPeerCategoryCorrespondents", []) + case .topPeerCategoryGroups: + return ("topPeerCategoryGroups", []) + case .topPeerCategoryChannels: + return ("topPeerCategoryChannels", []) + case .topPeerCategoryPhoneCalls: + return ("topPeerCategoryPhoneCalls", []) + case .topPeerCategoryForwardUsers: + return ("topPeerCategoryForwardUsers", []) + case .topPeerCategoryForwardChats: + return ("topPeerCategoryForwardChats", []) + } + } + + static func parse_topPeerCategoryBotsPM(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryBotsPM + } + static func parse_topPeerCategoryBotsInline(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryBotsInline + } + static func parse_topPeerCategoryCorrespondents(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryCorrespondents + } + static func parse_topPeerCategoryGroups(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryGroups + } + static func parse_topPeerCategoryChannels(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryChannels + } + static func parse_topPeerCategoryPhoneCalls(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryPhoneCalls + } + static func parse_topPeerCategoryForwardUsers(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryForwardUsers + } + static func parse_topPeerCategoryForwardChats(_ reader: BufferReader) -> TopPeerCategory? { + return Api.TopPeerCategory.topPeerCategoryForwardChats + } + + } + enum ChannelMessagesFilter: TypeConstructorDescription { + case channelMessagesFilterEmpty + case channelMessagesFilter(flags: Int32, ranges: [Api.MessageRange]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelMessagesFilterEmpty: + if boxed { + buffer.appendInt32(-1798033689) + } + + break + case .channelMessagesFilter(let flags, let ranges): + if boxed { + buffer.appendInt32(-847783593) + } + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(ranges.count)) + for item in ranges { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelMessagesFilterEmpty: + return ("channelMessagesFilterEmpty", []) + case .channelMessagesFilter(let flags, let ranges): + return ("channelMessagesFilter", [("flags", flags), ("ranges", ranges)]) + } + } + + static func parse_channelMessagesFilterEmpty(_ reader: BufferReader) -> ChannelMessagesFilter? { + return Api.ChannelMessagesFilter.channelMessagesFilterEmpty + } + static func parse_channelMessagesFilter(_ reader: BufferReader) -> ChannelMessagesFilter? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.MessageRange]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageRange.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelMessagesFilter.channelMessagesFilter(flags: _1!, ranges: _2!) + } + else { + return nil + } + } + + } + enum InputDocument: TypeConstructorDescription { + case inputDocumentEmpty + case inputDocument(id: Int64, accessHash: Int64, fileReference: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputDocumentEmpty: + if boxed { + buffer.appendInt32(1928391342) + } + + break + case .inputDocument(let id, let accessHash, let fileReference): + if boxed { + buffer.appendInt32(448771445) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputDocumentEmpty: + return ("inputDocumentEmpty", []) + case .inputDocument(let id, let accessHash, let fileReference): + return ("inputDocument", [("id", id), ("accessHash", accessHash), ("fileReference", fileReference)]) + } + } + + static func parse_inputDocumentEmpty(_ reader: BufferReader) -> InputDocument? { + return Api.InputDocument.inputDocumentEmpty + } + static func parse_inputDocument(_ reader: BufferReader) -> InputDocument? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputDocument.inputDocument(id: _1!, accessHash: _2!, fileReference: _3!) + } + else { + return nil + } + } + + } + enum PollAnswer: TypeConstructorDescription { + case pollAnswer(text: String, option: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pollAnswer(let text, let option): + if boxed { + buffer.appendInt32(1823064809) + } + serializeString(text, buffer: buffer, boxed: false) + serializeBytes(option, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pollAnswer(let text, let option): + return ("pollAnswer", [("text", text), ("option", option)]) + } + } + + static func parse_pollAnswer(_ reader: BufferReader) -> PollAnswer? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PollAnswer.pollAnswer(text: _1!, option: _2!) + } + else { + return nil + } + } + + } + enum SecureData: TypeConstructorDescription { + case secureData(data: Buffer, dataHash: Buffer, secret: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureData(let data, let dataHash, let secret): + if boxed { + buffer.appendInt32(-1964327229) + } + serializeBytes(data, buffer: buffer, boxed: false) + serializeBytes(dataHash, buffer: buffer, boxed: false) + serializeBytes(secret, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureData(let data, let dataHash, let secret): + return ("secureData", [("data", data), ("dataHash", dataHash), ("secret", secret)]) + } + } + + static func parse_secureData(_ reader: BufferReader) -> SecureData? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureData.secureData(data: _1!, dataHash: _2!, secret: _3!) + } + else { + return nil + } + } + + } + enum InputMedia: TypeConstructorDescription { + case inputMediaEmpty + case inputMediaGeoPoint(geoPoint: Api.InputGeoPoint) + case inputMediaGifExternal(url: String, q: String) + case inputMediaGame(id: Api.InputGame) + case inputMediaVenue(geoPoint: Api.InputGeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String) + case inputMediaInvoice(flags: Int32, title: String, description: String, photo: Api.InputWebDocument?, invoice: Api.Invoice, payload: Buffer, provider: String, providerData: Api.DataJSON, startParam: String) + case inputMediaUploadedPhoto(flags: Int32, file: Api.InputFile, stickers: [Api.InputDocument]?, ttlSeconds: Int32?) + case inputMediaUploadedDocument(flags: Int32, file: Api.InputFile, thumb: Api.InputFile?, mimeType: String, attributes: [Api.DocumentAttribute], stickers: [Api.InputDocument]?, ttlSeconds: Int32?) + case inputMediaPhoto(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?) + case inputMediaDocument(flags: Int32, id: Api.InputDocument, ttlSeconds: Int32?) + case inputMediaPhotoExternal(flags: Int32, url: String, ttlSeconds: Int32?) + case inputMediaDocumentExternal(flags: Int32, url: String, ttlSeconds: Int32?) + case inputMediaContact(phoneNumber: String, firstName: String, lastName: String, vcard: String) + case inputMediaPoll(poll: Api.Poll) + case inputMediaGeoLive(flags: Int32, geoPoint: Api.InputGeoPoint, period: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputMediaEmpty: + if boxed { + buffer.appendInt32(-1771768449) + } + + break + case .inputMediaGeoPoint(let geoPoint): + if boxed { + buffer.appendInt32(-104578748) + } + geoPoint.serialize(buffer, true) + break + case .inputMediaGifExternal(let url, let q): + if boxed { + buffer.appendInt32(1212395773) + } + serializeString(url, buffer: buffer, boxed: false) + serializeString(q, buffer: buffer, boxed: false) + break + case .inputMediaGame(let id): + if boxed { + buffer.appendInt32(-750828557) + } + id.serialize(buffer, true) + break + case .inputMediaVenue(let geoPoint, let title, let address, let provider, let venueId, let venueType): + if boxed { + buffer.appendInt32(-1052959727) + } + geoPoint.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + serializeString(venueType, buffer: buffer, boxed: false) + break + case .inputMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam): + if boxed { + buffer.appendInt32(-186607933) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} + invoice.serialize(buffer, true) + serializeBytes(payload, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + providerData.serialize(buffer, true) + serializeString(startParam, buffer: buffer, boxed: false) + break + case .inputMediaUploadedPhoto(let flags, let file, let stickers, let ttlSeconds): + if boxed { + buffer.appendInt32(505969924) + } + serializeInt32(flags, buffer: buffer, boxed: false) + file.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickers!.count)) + for item in stickers! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let ttlSeconds): + if boxed { + buffer.appendInt32(1530447553) + } + serializeInt32(flags, buffer: buffer, boxed: false) + file.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {thumb!.serialize(buffer, true)} + serializeString(mimeType, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickers!.count)) + for item in stickers! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaPhoto(let flags, let id, let ttlSeconds): + if boxed { + buffer.appendInt32(-1279654347) + } + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaDocument(let flags, let id, let ttlSeconds): + if boxed { + buffer.appendInt32(598418386) + } + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds): + if boxed { + buffer.appendInt32(-440664550) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds): + if boxed { + buffer.appendInt32(-78455655) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .inputMediaContact(let phoneNumber, let firstName, let lastName, let vcard): + if boxed { + buffer.appendInt32(-122978821) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(vcard, buffer: buffer, boxed: false) + break + case .inputMediaPoll(let poll): + if boxed { + buffer.appendInt32(112424539) + } + poll.serialize(buffer, true) + break + case .inputMediaGeoLive(let flags, let geoPoint, let period): + if boxed { + buffer.appendInt32(-833715459) + } + serializeInt32(flags, buffer: buffer, boxed: false) + geoPoint.serialize(buffer, true) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputMediaEmpty: + return ("inputMediaEmpty", []) + case .inputMediaGeoPoint(let geoPoint): + return ("inputMediaGeoPoint", [("geoPoint", geoPoint)]) + case .inputMediaGifExternal(let url, let q): + return ("inputMediaGifExternal", [("url", url), ("q", q)]) + case .inputMediaGame(let id): + return ("inputMediaGame", [("id", id)]) + case .inputMediaVenue(let geoPoint, let title, let address, let provider, let venueId, let venueType): + return ("inputMediaVenue", [("geoPoint", geoPoint), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType)]) + case .inputMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam): + return ("inputMediaInvoice", [("flags", flags), ("title", title), ("description", description), ("photo", photo), ("invoice", invoice), ("payload", payload), ("provider", provider), ("providerData", providerData), ("startParam", startParam)]) + case .inputMediaUploadedPhoto(let flags, let file, let stickers, let ttlSeconds): + return ("inputMediaUploadedPhoto", [("flags", flags), ("file", file), ("stickers", stickers), ("ttlSeconds", ttlSeconds)]) + case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let ttlSeconds): + return ("inputMediaUploadedDocument", [("flags", flags), ("file", file), ("thumb", thumb), ("mimeType", mimeType), ("attributes", attributes), ("stickers", stickers), ("ttlSeconds", ttlSeconds)]) + case .inputMediaPhoto(let flags, let id, let ttlSeconds): + return ("inputMediaPhoto", [("flags", flags), ("id", id), ("ttlSeconds", ttlSeconds)]) + case .inputMediaDocument(let flags, let id, let ttlSeconds): + return ("inputMediaDocument", [("flags", flags), ("id", id), ("ttlSeconds", ttlSeconds)]) + case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds): + return ("inputMediaPhotoExternal", [("flags", flags), ("url", url), ("ttlSeconds", ttlSeconds)]) + case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds): + return ("inputMediaDocumentExternal", [("flags", flags), ("url", url), ("ttlSeconds", ttlSeconds)]) + case .inputMediaContact(let phoneNumber, let firstName, let lastName, let vcard): + return ("inputMediaContact", [("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard)]) + case .inputMediaPoll(let poll): + return ("inputMediaPoll", [("poll", poll)]) + case .inputMediaGeoLive(let flags, let geoPoint, let period): + return ("inputMediaGeoLive", [("flags", flags), ("geoPoint", geoPoint), ("period", period)]) + } + } + + static func parse_inputMediaEmpty(_ reader: BufferReader) -> InputMedia? { + return Api.InputMedia.inputMediaEmpty + } + static func parse_inputMediaGeoPoint(_ reader: BufferReader) -> InputMedia? { + var _1: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + let _c1 = _1 != nil + if _c1 { + return Api.InputMedia.inputMediaGeoPoint(geoPoint: _1!) + } + else { + return nil + } + } + static func parse_inputMediaGifExternal(_ reader: BufferReader) -> InputMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputMedia.inputMediaGifExternal(url: _1!, q: _2!) + } + else { + return nil + } + } + static func parse_inputMediaGame(_ reader: BufferReader) -> InputMedia? { + var _1: Api.InputGame? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputGame + } + let _c1 = _1 != nil + if _c1 { + return Api.InputMedia.inputMediaGame(id: _1!) + } + else { + return nil + } + } + static func parse_inputMediaVenue(_ reader: BufferReader) -> InputMedia? { + var _1: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputMedia.inputMediaVenue(geoPoint: _1!, title: _2!, address: _3!, provider: _4!, venueId: _5!, venueType: _6!) + } + else { + return nil + } + } + static func parse_inputMediaInvoice(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.InputWebDocument? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InputWebDocument + } } + var _5: Api.Invoice? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Invoice + } + var _6: Buffer? + _6 = parseBytes(reader) + var _7: String? + _7 = parseString(reader) + var _8: Api.DataJSON? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.InputMedia.inputMediaInvoice(flags: _1!, title: _2!, description: _3!, photo: _4, invoice: _5!, payload: _6!, provider: _7!, providerData: _8!, startParam: _9!) + } + else { + return nil + } + } + static func parse_inputMediaUploadedPhoto(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputFile? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputFile + } + var _3: [Api.InputDocument]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputDocument.self) + } } + var _4: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputMedia.inputMediaUploadedPhoto(flags: _1!, file: _2!, stickers: _3, ttlSeconds: _4) + } + else { + return nil + } + } + static func parse_inputMediaUploadedDocument(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputFile? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputFile + } + var _3: Api.InputFile? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.InputFile + } } + var _4: String? + _4 = parseString(reader) + var _5: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + var _6: [Api.InputDocument]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputDocument.self) + } } + var _7: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_7 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.InputMedia.inputMediaUploadedDocument(flags: _1!, file: _2!, thumb: _3, mimeType: _4!, attributes: _5!, stickers: _6, ttlSeconds: _7) + } + else { + return nil + } + } + static func parse_inputMediaPhoto(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputPhoto? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputPhoto + } + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputMedia.inputMediaPhoto(flags: _1!, id: _2!, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_inputMediaDocument(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputDocument? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputDocument + } + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputMedia.inputMediaDocument(flags: _1!, id: _2!, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_inputMediaPhotoExternal(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputMedia.inputMediaPhotoExternal(flags: _1!, url: _2!, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_inputMediaDocumentExternal(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputMedia.inputMediaDocumentExternal(flags: _1!, url: _2!, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_inputMediaContact(_ reader: BufferReader) -> InputMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputMedia.inputMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, vcard: _4!) + } + else { + return nil + } + } + static func parse_inputMediaPoll(_ reader: BufferReader) -> InputMedia? { + var _1: Api.Poll? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Poll + } + let _c1 = _1 != nil + if _c1 { + return Api.InputMedia.inputMediaPoll(poll: _1!) + } + else { + return nil + } + } + static func parse_inputMediaGeoLive(_ reader: BufferReader) -> InputMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _3: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputMedia.inputMediaGeoLive(flags: _1!, geoPoint: _2!, period: _3) + } + else { + return nil + } + } + + } + enum InputPeer: TypeConstructorDescription { + case inputPeerEmpty + case inputPeerSelf + case inputPeerChat(chatId: Int32) + case inputPeerUser(userId: Int32, accessHash: Int64) + case inputPeerChannel(channelId: Int32, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPeerEmpty: + if boxed { + buffer.appendInt32(2134579434) + } + + break + case .inputPeerSelf: + if boxed { + buffer.appendInt32(2107670217) + } + + break + case .inputPeerChat(let chatId): + if boxed { + buffer.appendInt32(396093539) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + break + case .inputPeerUser(let userId, let accessHash): + if boxed { + buffer.appendInt32(2072935910) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputPeerChannel(let channelId, let accessHash): + if boxed { + buffer.appendInt32(548253432) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPeerEmpty: + return ("inputPeerEmpty", []) + case .inputPeerSelf: + return ("inputPeerSelf", []) + case .inputPeerChat(let chatId): + return ("inputPeerChat", [("chatId", chatId)]) + case .inputPeerUser(let userId, let accessHash): + return ("inputPeerUser", [("userId", userId), ("accessHash", accessHash)]) + case .inputPeerChannel(let channelId, let accessHash): + return ("inputPeerChannel", [("channelId", channelId), ("accessHash", accessHash)]) + } + } + + static func parse_inputPeerEmpty(_ reader: BufferReader) -> InputPeer? { + return Api.InputPeer.inputPeerEmpty + } + static func parse_inputPeerSelf(_ reader: BufferReader) -> InputPeer? { + return Api.InputPeer.inputPeerSelf + } + static func parse_inputPeerChat(_ reader: BufferReader) -> InputPeer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.InputPeer.inputPeerChat(chatId: _1!) + } + else { + return nil + } + } + static func parse_inputPeerUser(_ reader: BufferReader) -> InputPeer? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPeer.inputPeerUser(userId: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputPeerChannel(_ reader: BufferReader) -> InputPeer? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPeer.inputPeerChannel(channelId: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum Contact: TypeConstructorDescription { + case contact(userId: Int32, mutual: Api.Bool) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contact(let userId, let mutual): + if boxed { + buffer.appendInt32(-116274796) + } + serializeInt32(userId, buffer: buffer, boxed: false) + mutual.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contact(let userId, let mutual): + return ("contact", [("userId", userId), ("mutual", mutual)]) + } + } + + static func parse_contact(_ reader: BufferReader) -> Contact? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Bool? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Contact.contact(userId: _1!, mutual: _2!) + } + else { + return nil + } + } + + } + enum FileHash: TypeConstructorDescription { + case fileHash(offset: Int32, limit: Int32, hash: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileHash(let offset, let limit, let hash): + if boxed { + buffer.appendInt32(1648543603) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .fileHash(let offset, let limit, let hash): + return ("fileHash", [("offset", offset), ("limit", limit), ("hash", hash)]) + } + } + + static func parse_fileHash(_ reader: BufferReader) -> FileHash? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.FileHash.fileHash(offset: _1!, limit: _2!, hash: _3!) + } + else { + return nil + } + } + + } + enum BotInlineResult: TypeConstructorDescription { + case botInlineMediaResult(flags: Int32, id: String, type: String, photo: Api.Photo?, document: Api.Document?, title: String?, description: String?, sendMessage: Api.BotInlineMessage) + case botInlineResult(flags: Int32, id: String, type: String, title: String?, description: String?, url: String?, thumb: Api.WebDocument?, content: Api.WebDocument?, sendMessage: Api.BotInlineMessage) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): + if boxed { + buffer.appendInt32(400266251) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + sendMessage.serialize(buffer, true) + break + case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + if boxed { + buffer.appendInt32(295067450) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {content!.serialize(buffer, true)} + sendMessage.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botInlineMediaResult(let flags, let id, let type, let photo, let document, let title, let description, let sendMessage): + return ("botInlineMediaResult", [("flags", flags), ("id", id), ("type", type), ("photo", photo), ("document", document), ("title", title), ("description", description), ("sendMessage", sendMessage)]) + case .botInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + return ("botInlineResult", [("flags", flags), ("id", id), ("type", type), ("title", title), ("description", description), ("url", url), ("thumb", thumb), ("content", content), ("sendMessage", sendMessage)]) + } + } + + static func parse_botInlineMediaResult(_ reader: BufferReader) -> BotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.Photo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _5: Api.Document? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _6: String? + if Int(_1!) & Int(1 << 2) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) } + var _8: Api.BotInlineMessage? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.BotInlineResult.botInlineMediaResult(flags: _1!, id: _2!, type: _3!, photo: _4, document: _5, title: _6, description: _7, sendMessage: _8!) + } + else { + return nil + } + } + static func parse_botInlineResult(_ reader: BufferReader) -> BotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: Api.WebDocument? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.WebDocument + } } + var _8: Api.WebDocument? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.WebDocument + } } + var _9: Api.BotInlineMessage? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.BotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.BotInlineResult.botInlineResult(flags: _1!, id: _2!, type: _3!, title: _4, description: _5, url: _6, thumb: _7, content: _8, sendMessage: _9!) + } + else { + return nil + } + } + + } + enum InputSingleMedia: TypeConstructorDescription { + case inputSingleMedia(flags: Int32, media: Api.InputMedia, randomId: Int64, message: String, entities: [Api.MessageEntity]?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputSingleMedia(let flags, let media, let randomId, let message, let entities): + if boxed { + buffer.appendInt32(482797855) + } + serializeInt32(flags, buffer: buffer, boxed: false) + media.serialize(buffer, true) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputSingleMedia(let flags, let media, let randomId, let message, let entities): + return ("inputSingleMedia", [("flags", flags), ("media", media), ("randomId", randomId), ("message", message), ("entities", entities)]) + } + } + + static func parse_inputSingleMedia(_ reader: BufferReader) -> InputSingleMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputMedia? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputMedia + } + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.InputSingleMedia.inputSingleMedia(flags: _1!, media: _2!, randomId: _3!, message: _4!, entities: _5) + } + else { + return nil + } + } + + } + enum InputPrivacyRule: TypeConstructorDescription { + case inputPrivacyValueAllowContacts + case inputPrivacyValueAllowAll + case inputPrivacyValueAllowUsers(users: [Api.InputUser]) + case inputPrivacyValueDisallowContacts + case inputPrivacyValueDisallowAll + case inputPrivacyValueDisallowUsers(users: [Api.InputUser]) + case inputPrivacyValueAllowChatParticipants(chats: [Int32]) + case inputPrivacyValueDisallowChatParticipants(chats: [Int32]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPrivacyValueAllowContacts: + if boxed { + buffer.appendInt32(218751099) + } + + break + case .inputPrivacyValueAllowAll: + if boxed { + buffer.appendInt32(407582158) + } + + break + case .inputPrivacyValueAllowUsers(let users): + if boxed { + buffer.appendInt32(320652927) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .inputPrivacyValueDisallowContacts: + if boxed { + buffer.appendInt32(195371015) + } + + break + case .inputPrivacyValueDisallowAll: + if boxed { + buffer.appendInt32(-697604407) + } + + break + case .inputPrivacyValueDisallowUsers(let users): + if boxed { + buffer.appendInt32(-1877932953) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .inputPrivacyValueAllowChatParticipants(let chats): + if boxed { + buffer.appendInt32(1283572154) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .inputPrivacyValueDisallowChatParticipants(let chats): + if boxed { + buffer.appendInt32(-668769361) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPrivacyValueAllowContacts: + return ("inputPrivacyValueAllowContacts", []) + case .inputPrivacyValueAllowAll: + return ("inputPrivacyValueAllowAll", []) + case .inputPrivacyValueAllowUsers(let users): + return ("inputPrivacyValueAllowUsers", [("users", users)]) + case .inputPrivacyValueDisallowContacts: + return ("inputPrivacyValueDisallowContacts", []) + case .inputPrivacyValueDisallowAll: + return ("inputPrivacyValueDisallowAll", []) + case .inputPrivacyValueDisallowUsers(let users): + return ("inputPrivacyValueDisallowUsers", [("users", users)]) + case .inputPrivacyValueAllowChatParticipants(let chats): + return ("inputPrivacyValueAllowChatParticipants", [("chats", chats)]) + case .inputPrivacyValueDisallowChatParticipants(let chats): + return ("inputPrivacyValueDisallowChatParticipants", [("chats", chats)]) + } + } + + static func parse_inputPrivacyValueAllowContacts(_ reader: BufferReader) -> InputPrivacyRule? { + return Api.InputPrivacyRule.inputPrivacyValueAllowContacts + } + static func parse_inputPrivacyValueAllowAll(_ reader: BufferReader) -> InputPrivacyRule? { + return Api.InputPrivacyRule.inputPrivacyValueAllowAll + } + static func parse_inputPrivacyValueAllowUsers(_ reader: BufferReader) -> InputPrivacyRule? { + var _1: [Api.InputUser]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputUser.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.InputPrivacyRule.inputPrivacyValueAllowUsers(users: _1!) + } + else { + return nil + } + } + static func parse_inputPrivacyValueDisallowContacts(_ reader: BufferReader) -> InputPrivacyRule? { + return Api.InputPrivacyRule.inputPrivacyValueDisallowContacts + } + static func parse_inputPrivacyValueDisallowAll(_ reader: BufferReader) -> InputPrivacyRule? { + return Api.InputPrivacyRule.inputPrivacyValueDisallowAll + } + static func parse_inputPrivacyValueDisallowUsers(_ reader: BufferReader) -> InputPrivacyRule? { + var _1: [Api.InputUser]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputUser.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.InputPrivacyRule.inputPrivacyValueDisallowUsers(users: _1!) + } + else { + return nil + } + } + static func parse_inputPrivacyValueAllowChatParticipants(_ reader: BufferReader) -> InputPrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.InputPrivacyRule.inputPrivacyValueAllowChatParticipants(chats: _1!) + } + else { + return nil + } + } + static func parse_inputPrivacyValueDisallowChatParticipants(_ reader: BufferReader) -> InputPrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.InputPrivacyRule.inputPrivacyValueDisallowChatParticipants(chats: _1!) + } + else { + return nil + } + } + + } + enum ChannelAdminLogEventAction: TypeConstructorDescription { + case channelAdminLogEventActionChangeTitle(prevValue: String, newValue: String) + case channelAdminLogEventActionChangeAbout(prevValue: String, newValue: String) + case channelAdminLogEventActionChangeUsername(prevValue: String, newValue: String) + case channelAdminLogEventActionToggleInvites(newValue: Api.Bool) + case channelAdminLogEventActionToggleSignatures(newValue: Api.Bool) + case channelAdminLogEventActionUpdatePinned(message: Api.Message) + case channelAdminLogEventActionEditMessage(prevMessage: Api.Message, newMessage: Api.Message) + case channelAdminLogEventActionDeleteMessage(message: Api.Message) + case channelAdminLogEventActionParticipantJoin + case channelAdminLogEventActionParticipantLeave + case channelAdminLogEventActionParticipantInvite(participant: Api.ChannelParticipant) + case channelAdminLogEventActionParticipantToggleBan(prevParticipant: Api.ChannelParticipant, newParticipant: Api.ChannelParticipant) + case channelAdminLogEventActionParticipantToggleAdmin(prevParticipant: Api.ChannelParticipant, newParticipant: Api.ChannelParticipant) + case channelAdminLogEventActionChangeStickerSet(prevStickerset: Api.InputStickerSet, newStickerset: Api.InputStickerSet) + case channelAdminLogEventActionTogglePreHistoryHidden(newValue: Api.Bool) + case channelAdminLogEventActionDefaultBannedRights(prevBannedRights: Api.ChatBannedRights, newBannedRights: Api.ChatBannedRights) + case channelAdminLogEventActionStopPoll(message: Api.Message) + case channelAdminLogEventActionChangePhoto(prevPhoto: Api.Photo, newPhoto: Api.Photo) + case channelAdminLogEventActionChangeLinkedChat(prevValue: Int32, newValue: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelAdminLogEventActionChangeTitle(let prevValue, let newValue): + if boxed { + buffer.appendInt32(-421545947) + } + serializeString(prevValue, buffer: buffer, boxed: false) + serializeString(newValue, buffer: buffer, boxed: false) + break + case .channelAdminLogEventActionChangeAbout(let prevValue, let newValue): + if boxed { + buffer.appendInt32(1427671598) + } + serializeString(prevValue, buffer: buffer, boxed: false) + serializeString(newValue, buffer: buffer, boxed: false) + break + case .channelAdminLogEventActionChangeUsername(let prevValue, let newValue): + if boxed { + buffer.appendInt32(1783299128) + } + serializeString(prevValue, buffer: buffer, boxed: false) + serializeString(newValue, buffer: buffer, boxed: false) + break + case .channelAdminLogEventActionToggleInvites(let newValue): + if boxed { + buffer.appendInt32(460916654) + } + newValue.serialize(buffer, true) + break + case .channelAdminLogEventActionToggleSignatures(let newValue): + if boxed { + buffer.appendInt32(648939889) + } + newValue.serialize(buffer, true) + break + case .channelAdminLogEventActionUpdatePinned(let message): + if boxed { + buffer.appendInt32(-370660328) + } + message.serialize(buffer, true) + break + case .channelAdminLogEventActionEditMessage(let prevMessage, let newMessage): + if boxed { + buffer.appendInt32(1889215493) + } + prevMessage.serialize(buffer, true) + newMessage.serialize(buffer, true) + break + case .channelAdminLogEventActionDeleteMessage(let message): + if boxed { + buffer.appendInt32(1121994683) + } + message.serialize(buffer, true) + break + case .channelAdminLogEventActionParticipantJoin: + if boxed { + buffer.appendInt32(405815507) + } + + break + case .channelAdminLogEventActionParticipantLeave: + if boxed { + buffer.appendInt32(-124291086) + } + + break + case .channelAdminLogEventActionParticipantInvite(let participant): + if boxed { + buffer.appendInt32(-484690728) + } + participant.serialize(buffer, true) + break + case .channelAdminLogEventActionParticipantToggleBan(let prevParticipant, let newParticipant): + if boxed { + buffer.appendInt32(-422036098) + } + prevParticipant.serialize(buffer, true) + newParticipant.serialize(buffer, true) + break + case .channelAdminLogEventActionParticipantToggleAdmin(let prevParticipant, let newParticipant): + if boxed { + buffer.appendInt32(-714643696) + } + prevParticipant.serialize(buffer, true) + newParticipant.serialize(buffer, true) + break + case .channelAdminLogEventActionChangeStickerSet(let prevStickerset, let newStickerset): + if boxed { + buffer.appendInt32(-1312568665) + } + prevStickerset.serialize(buffer, true) + newStickerset.serialize(buffer, true) + break + case .channelAdminLogEventActionTogglePreHistoryHidden(let newValue): + if boxed { + buffer.appendInt32(1599903217) + } + newValue.serialize(buffer, true) + break + case .channelAdminLogEventActionDefaultBannedRights(let prevBannedRights, let newBannedRights): + if boxed { + buffer.appendInt32(771095562) + } + prevBannedRights.serialize(buffer, true) + newBannedRights.serialize(buffer, true) + break + case .channelAdminLogEventActionStopPoll(let message): + if boxed { + buffer.appendInt32(-1895328189) + } + message.serialize(buffer, true) + break + case .channelAdminLogEventActionChangePhoto(let prevPhoto, let newPhoto): + if boxed { + buffer.appendInt32(1129042607) + } + prevPhoto.serialize(buffer, true) + newPhoto.serialize(buffer, true) + break + case .channelAdminLogEventActionChangeLinkedChat(let prevValue, let newValue): + if boxed { + buffer.appendInt32(-1569748965) + } + serializeInt32(prevValue, buffer: buffer, boxed: false) + serializeInt32(newValue, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelAdminLogEventActionChangeTitle(let prevValue, let newValue): + return ("channelAdminLogEventActionChangeTitle", [("prevValue", prevValue), ("newValue", newValue)]) + case .channelAdminLogEventActionChangeAbout(let prevValue, let newValue): + return ("channelAdminLogEventActionChangeAbout", [("prevValue", prevValue), ("newValue", newValue)]) + case .channelAdminLogEventActionChangeUsername(let prevValue, let newValue): + return ("channelAdminLogEventActionChangeUsername", [("prevValue", prevValue), ("newValue", newValue)]) + case .channelAdminLogEventActionToggleInvites(let newValue): + return ("channelAdminLogEventActionToggleInvites", [("newValue", newValue)]) + case .channelAdminLogEventActionToggleSignatures(let newValue): + return ("channelAdminLogEventActionToggleSignatures", [("newValue", newValue)]) + case .channelAdminLogEventActionUpdatePinned(let message): + return ("channelAdminLogEventActionUpdatePinned", [("message", message)]) + case .channelAdminLogEventActionEditMessage(let prevMessage, let newMessage): + return ("channelAdminLogEventActionEditMessage", [("prevMessage", prevMessage), ("newMessage", newMessage)]) + case .channelAdminLogEventActionDeleteMessage(let message): + return ("channelAdminLogEventActionDeleteMessage", [("message", message)]) + case .channelAdminLogEventActionParticipantJoin: + return ("channelAdminLogEventActionParticipantJoin", []) + case .channelAdminLogEventActionParticipantLeave: + return ("channelAdminLogEventActionParticipantLeave", []) + case .channelAdminLogEventActionParticipantInvite(let participant): + return ("channelAdminLogEventActionParticipantInvite", [("participant", participant)]) + case .channelAdminLogEventActionParticipantToggleBan(let prevParticipant, let newParticipant): + return ("channelAdminLogEventActionParticipantToggleBan", [("prevParticipant", prevParticipant), ("newParticipant", newParticipant)]) + case .channelAdminLogEventActionParticipantToggleAdmin(let prevParticipant, let newParticipant): + return ("channelAdminLogEventActionParticipantToggleAdmin", [("prevParticipant", prevParticipant), ("newParticipant", newParticipant)]) + case .channelAdminLogEventActionChangeStickerSet(let prevStickerset, let newStickerset): + return ("channelAdminLogEventActionChangeStickerSet", [("prevStickerset", prevStickerset), ("newStickerset", newStickerset)]) + case .channelAdminLogEventActionTogglePreHistoryHidden(let newValue): + return ("channelAdminLogEventActionTogglePreHistoryHidden", [("newValue", newValue)]) + case .channelAdminLogEventActionDefaultBannedRights(let prevBannedRights, let newBannedRights): + return ("channelAdminLogEventActionDefaultBannedRights", [("prevBannedRights", prevBannedRights), ("newBannedRights", newBannedRights)]) + case .channelAdminLogEventActionStopPoll(let message): + return ("channelAdminLogEventActionStopPoll", [("message", message)]) + case .channelAdminLogEventActionChangePhoto(let prevPhoto, let newPhoto): + return ("channelAdminLogEventActionChangePhoto", [("prevPhoto", prevPhoto), ("newPhoto", newPhoto)]) + case .channelAdminLogEventActionChangeLinkedChat(let prevValue, let newValue): + return ("channelAdminLogEventActionChangeLinkedChat", [("prevValue", prevValue), ("newValue", newValue)]) + } + } + + static func parse_channelAdminLogEventActionChangeTitle(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeTitle(prevValue: _1!, newValue: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionChangeAbout(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeAbout(prevValue: _1!, newValue: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionChangeUsername(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeUsername(prevValue: _1!, newValue: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionToggleInvites(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Bool? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionToggleInvites(newValue: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionToggleSignatures(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Bool? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionToggleSignatures(newValue: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionUpdatePinned(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionUpdatePinned(message: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionEditMessage(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + var _2: Api.Message? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Message + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionEditMessage(prevMessage: _1!, newMessage: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionDeleteMessage(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionDeleteMessage(message: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionParticipantJoin(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionParticipantJoin + } + static func parse_channelAdminLogEventActionParticipantLeave(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionParticipantLeave + } + static func parse_channelAdminLogEventActionParticipantInvite(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionParticipantInvite(participant: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionParticipantToggleBan(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + var _2: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionParticipantToggleBan(prevParticipant: _1!, newParticipant: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionParticipantToggleAdmin(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + var _2: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionParticipantToggleAdmin(prevParticipant: _1!, newParticipant: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionChangeStickerSet(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.InputStickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputStickerSet + } + var _2: Api.InputStickerSet? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputStickerSet + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeStickerSet(prevStickerset: _1!, newStickerset: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionTogglePreHistoryHidden(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Bool? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionTogglePreHistoryHidden(newValue: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionDefaultBannedRights(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.ChatBannedRights? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } + var _2: Api.ChatBannedRights? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.ChatBannedRights + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionDefaultBannedRights(prevBannedRights: _1!, newBannedRights: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionStopPoll(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionStopPoll(message: _1!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionChangePhoto(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Api.Photo? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _2: Api.Photo? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Photo + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangePhoto(prevPhoto: _1!, newPhoto: _2!) + } + else { + return nil + } + } + static func parse_channelAdminLogEventActionChangeLinkedChat(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionChangeLinkedChat(prevValue: _1!, newValue: _2!) + } + else { + return nil + } + } + + } + enum SecurePlainData: TypeConstructorDescription { + case securePlainPhone(phone: String) + case securePlainEmail(email: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .securePlainPhone(let phone): + if boxed { + buffer.appendInt32(2103482845) + } + serializeString(phone, buffer: buffer, boxed: false) + break + case .securePlainEmail(let email): + if boxed { + buffer.appendInt32(569137759) + } + serializeString(email, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .securePlainPhone(let phone): + return ("securePlainPhone", [("phone", phone)]) + case .securePlainEmail(let email): + return ("securePlainEmail", [("email", email)]) + } + } + + static func parse_securePlainPhone(_ reader: BufferReader) -> SecurePlainData? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.SecurePlainData.securePlainPhone(phone: _1!) + } + else { + return nil + } + } + static func parse_securePlainEmail(_ reader: BufferReader) -> SecurePlainData? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.SecurePlainData.securePlainEmail(email: _1!) + } + else { + return nil + } + } + + } + enum PageTableCell: TypeConstructorDescription { + case pageTableCell(flags: Int32, text: Api.RichText?, colspan: Int32?, rowspan: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageTableCell(let flags, let text, let colspan, let rowspan): + if boxed { + buffer.appendInt32(878078826) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 7) != 0 {text!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(colspan!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(rowspan!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageTableCell(let flags, let text, let colspan, let rowspan): + return ("pageTableCell", [("flags", flags), ("text", text), ("colspan", colspan), ("rowspan", rowspan)]) + } + } + + static func parse_pageTableCell(_ reader: BufferReader) -> PageTableCell? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.RichText? + if Int(_1!) & Int(1 << 7) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } } + var _3: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() } + var _4: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 7) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.PageTableCell.pageTableCell(flags: _1!, text: _2, colspan: _3, rowspan: _4) + } + else { + return nil + } + } + + } + enum ChatBannedRights: TypeConstructorDescription { + case chatBannedRights(flags: Int32, untilDate: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatBannedRights(let flags, let untilDate): + if boxed { + buffer.appendInt32(-1626209256) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(untilDate, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatBannedRights(let flags, let untilDate): + return ("chatBannedRights", [("flags", flags), ("untilDate", untilDate)]) + } + } + + static func parse_chatBannedRights(_ reader: BufferReader) -> ChatBannedRights? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChatBannedRights.chatBannedRights(flags: _1!, untilDate: _2!) + } + else { + return nil + } + } + + } + enum LabeledPrice: TypeConstructorDescription { + case labeledPrice(label: String, amount: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .labeledPrice(let label, let amount): + if boxed { + buffer.appendInt32(-886477832) + } + serializeString(label, buffer: buffer, boxed: false) + serializeInt64(amount, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .labeledPrice(let label, let amount): + return ("labeledPrice", [("label", label), ("amount", amount)]) + } + } + + static func parse_labeledPrice(_ reader: BufferReader) -> LabeledPrice? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.LabeledPrice.labeledPrice(label: _1!, amount: _2!) + } + else { + return nil + } + } + + } + enum InputSecureValue: TypeConstructorDescription { + case inputSecureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.InputSecureFile?, reverseSide: Api.InputSecureFile?, selfie: Api.InputSecureFile?, translation: [Api.InputSecureFile]?, files: [Api.InputSecureFile]?, plainData: Api.SecurePlainData?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData): + if boxed { + buffer.appendInt32(-618540889) + } + serializeInt32(flags, buffer: buffer, boxed: false) + type.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {data!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {frontSide!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {reverseSide!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {selfie!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(translation!.count)) + for item in translation! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(files!.count)) + for item in files! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 5) != 0 {plainData!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData): + return ("inputSecureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("translation", translation), ("files", files), ("plainData", plainData)]) + } + } + + static func parse_inputSecureValue(_ reader: BufferReader) -> InputSecureValue? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureValueType? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _3: Api.SecureData? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.SecureData + } } + var _4: Api.InputSecureFile? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InputSecureFile + } } + var _5: Api.InputSecureFile? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.InputSecureFile + } } + var _6: Api.InputSecureFile? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.InputSecureFile + } } + var _7: [Api.InputSecureFile]? + if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) + } } + var _8: [Api.InputSecureFile]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) + } } + var _9: Api.SecurePlainData? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.SecurePlainData + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.InputSecureValue.inputSecureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, translation: _7, files: _8, plainData: _9) + } + else { + return nil + } + } + + } + enum ReportReason: TypeConstructorDescription { + case inputReportReasonSpam + case inputReportReasonViolence + case inputReportReasonPornography + case inputReportReasonOther(text: String) + case inputReportReasonCopyright + case inputReportReasonChildAbuse + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputReportReasonSpam: + if boxed { + buffer.appendInt32(1490799288) + } + + break + case .inputReportReasonViolence: + if boxed { + buffer.appendInt32(505595789) + } + + break + case .inputReportReasonPornography: + if boxed { + buffer.appendInt32(777640226) + } + + break + case .inputReportReasonOther(let text): + if boxed { + buffer.appendInt32(-512463606) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .inputReportReasonCopyright: + if boxed { + buffer.appendInt32(-1685456582) + } + + break + case .inputReportReasonChildAbuse: + if boxed { + buffer.appendInt32(-1376497949) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputReportReasonSpam: + return ("inputReportReasonSpam", []) + case .inputReportReasonViolence: + return ("inputReportReasonViolence", []) + case .inputReportReasonPornography: + return ("inputReportReasonPornography", []) + case .inputReportReasonOther(let text): + return ("inputReportReasonOther", [("text", text)]) + case .inputReportReasonCopyright: + return ("inputReportReasonCopyright", []) + case .inputReportReasonChildAbuse: + return ("inputReportReasonChildAbuse", []) + } + } + + static func parse_inputReportReasonSpam(_ reader: BufferReader) -> ReportReason? { + return Api.ReportReason.inputReportReasonSpam + } + static func parse_inputReportReasonViolence(_ reader: BufferReader) -> ReportReason? { + return Api.ReportReason.inputReportReasonViolence + } + static func parse_inputReportReasonPornography(_ reader: BufferReader) -> ReportReason? { + return Api.ReportReason.inputReportReasonPornography + } + static func parse_inputReportReasonOther(_ reader: BufferReader) -> ReportReason? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ReportReason.inputReportReasonOther(text: _1!) + } + else { + return nil + } + } + static func parse_inputReportReasonCopyright(_ reader: BufferReader) -> ReportReason? { + return Api.ReportReason.inputReportReasonCopyright + } + static func parse_inputReportReasonChildAbuse(_ reader: BufferReader) -> ReportReason? { + return Api.ReportReason.inputReportReasonChildAbuse + } + + } + enum InputEncryptedChat: TypeConstructorDescription { + case inputEncryptedChat(chatId: Int32, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputEncryptedChat(let chatId, let accessHash): + if boxed { + buffer.appendInt32(-247351839) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputEncryptedChat(let chatId, let accessHash): + return ("inputEncryptedChat", [("chatId", chatId), ("accessHash", accessHash)]) + } + } + + static func parse_inputEncryptedChat(_ reader: BufferReader) -> InputEncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputEncryptedChat.inputEncryptedChat(chatId: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum PageTableRow: TypeConstructorDescription { + case pageTableRow(cells: [Api.PageTableCell]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageTableRow(let cells): + if boxed { + buffer.appendInt32(-524237339) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(cells.count)) + for item in cells { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageTableRow(let cells): + return ("pageTableRow", [("cells", cells)]) + } + } + + static func parse_pageTableRow(_ reader: BufferReader) -> PageTableRow? { + var _1: [Api.PageTableCell]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageTableCell.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PageTableRow.pageTableRow(cells: _1!) + } + else { + return nil + } + } + + } + enum DraftMessage: TypeConstructorDescription { + case draftMessage(flags: Int32, replyToMsgId: Int32?, message: String, entities: [Api.MessageEntity]?, date: Int32) + case draftMessageEmpty(flags: Int32, date: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .draftMessage(let flags, let replyToMsgId, let message, let entities, let date): + if boxed { + buffer.appendInt32(-40996577) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + serializeInt32(date, buffer: buffer, boxed: false) + break + case .draftMessageEmpty(let flags, let date): + if boxed { + buffer.appendInt32(453805082) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(date!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .draftMessage(let flags, let replyToMsgId, let message, let entities, let date): + return ("draftMessage", [("flags", flags), ("replyToMsgId", replyToMsgId), ("message", message), ("entities", entities), ("date", date)]) + case .draftMessageEmpty(let flags, let date): + return ("draftMessageEmpty", [("flags", flags), ("date", date)]) + } + } + + static func parse_draftMessage(_ reader: BufferReader) -> DraftMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: String? + _3 = parseString(reader) + var _4: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.DraftMessage.draftMessage(flags: _1!, replyToMsgId: _2, message: _3!, entities: _4, date: _5!) + } + else { + return nil + } + } + static func parse_draftMessageEmpty(_ reader: BufferReader) -> DraftMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + if _c1 && _c2 { + return Api.DraftMessage.draftMessageEmpty(flags: _1!, date: _2) + } + else { + return nil + } + } + + } + enum EncryptedFile: TypeConstructorDescription { + case encryptedFileEmpty + case encryptedFile(id: Int64, accessHash: Int64, size: Int32, dcId: Int32, keyFingerprint: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .encryptedFileEmpty: + if boxed { + buffer.appendInt32(-1038136962) + } + + break + case .encryptedFile(let id, let accessHash, let size, let dcId, let keyFingerprint): + if boxed { + buffer.appendInt32(1248893260) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt32(keyFingerprint, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .encryptedFileEmpty: + return ("encryptedFileEmpty", []) + case .encryptedFile(let id, let accessHash, let size, let dcId, let keyFingerprint): + return ("encryptedFile", [("id", id), ("accessHash", accessHash), ("size", size), ("dcId", dcId), ("keyFingerprint", keyFingerprint)]) + } + } + + static func parse_encryptedFileEmpty(_ reader: BufferReader) -> EncryptedFile? { + return Api.EncryptedFile.encryptedFileEmpty + } + static func parse_encryptedFile(_ reader: BufferReader) -> EncryptedFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.EncryptedFile.encryptedFile(id: _1!, accessHash: _2!, size: _3!, dcId: _4!, keyFingerprint: _5!) + } + else { + return nil + } + } + + } + enum SecureValueError: TypeConstructorDescription { + case secureValueErrorData(type: Api.SecureValueType, dataHash: Buffer, field: String, text: String) + case secureValueErrorFrontSide(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorReverseSide(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorSelfie(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorFile(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorFiles(type: Api.SecureValueType, fileHash: [Buffer], text: String) + case secureValueError(type: Api.SecureValueType, hash: Buffer, text: String) + case secureValueErrorTranslationFile(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorTranslationFiles(type: Api.SecureValueType, fileHash: [Buffer], text: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValueErrorData(let type, let dataHash, let field, let text): + if boxed { + buffer.appendInt32(-391902247) + } + type.serialize(buffer, true) + serializeBytes(dataHash, buffer: buffer, boxed: false) + serializeString(field, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorFrontSide(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(12467706) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorReverseSide(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(-2037765467) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorSelfie(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(-449327402) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorFile(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(2054162547) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorFiles(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(1717706985) + } + type.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(fileHash.count)) + for item in fileHash { + serializeBytes(item, buffer: buffer, boxed: false) + } + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueError(let type, let hash, let text): + if boxed { + buffer.appendInt32(-2036501105) + } + type.serialize(buffer, true) + serializeBytes(hash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorTranslationFile(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(-1592506512) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorTranslationFiles(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(878931416) + } + type.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(fileHash.count)) + for item in fileHash { + serializeBytes(item, buffer: buffer, boxed: false) + } + serializeString(text, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureValueErrorData(let type, let dataHash, let field, let text): + return ("secureValueErrorData", [("type", type), ("dataHash", dataHash), ("field", field), ("text", text)]) + case .secureValueErrorFrontSide(let type, let fileHash, let text): + return ("secureValueErrorFrontSide", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorReverseSide(let type, let fileHash, let text): + return ("secureValueErrorReverseSide", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorSelfie(let type, let fileHash, let text): + return ("secureValueErrorSelfie", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorFile(let type, let fileHash, let text): + return ("secureValueErrorFile", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorFiles(let type, let fileHash, let text): + return ("secureValueErrorFiles", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueError(let type, let hash, let text): + return ("secureValueError", [("type", type), ("hash", hash), ("text", text)]) + case .secureValueErrorTranslationFile(let type, let fileHash, let text): + return ("secureValueErrorTranslationFile", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorTranslationFiles(let type, let fileHash, let text): + return ("secureValueErrorTranslationFiles", [("type", type), ("fileHash", fileHash), ("text", text)]) + } + } + + static func parse_secureValueErrorData(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.SecureValueError.secureValueErrorData(type: _1!, dataHash: _2!, field: _3!, text: _4!) + } + else { + return nil + } + } + static func parse_secureValueErrorFrontSide(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorFrontSide(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorReverseSide(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorReverseSide(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorSelfie(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorSelfie(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorFile(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorFile(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorFiles(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: [Buffer]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self) + } + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorFiles(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueError(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueError(type: _1!, hash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorTranslationFile(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorTranslationFile(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorTranslationFiles(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: [Buffer]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self) + } + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorTranslationFiles(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + + } + enum NotifyPeer: TypeConstructorDescription { + case notifyPeer(peer: Api.Peer) + case notifyUsers + case notifyChats + case notifyBroadcasts + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .notifyPeer(let peer): + if boxed { + buffer.appendInt32(-1613493288) + } + peer.serialize(buffer, true) + break + case .notifyUsers: + if boxed { + buffer.appendInt32(-1261946036) + } + + break + case .notifyChats: + if boxed { + buffer.appendInt32(-1073230141) + } + + break + case .notifyBroadcasts: + if boxed { + buffer.appendInt32(-703403793) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .notifyPeer(let peer): + return ("notifyPeer", [("peer", peer)]) + case .notifyUsers: + return ("notifyUsers", []) + case .notifyChats: + return ("notifyChats", []) + case .notifyBroadcasts: + return ("notifyBroadcasts", []) + } + } + + static func parse_notifyPeer(_ reader: BufferReader) -> NotifyPeer? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + let _c1 = _1 != nil + if _c1 { + return Api.NotifyPeer.notifyPeer(peer: _1!) + } + else { + return nil + } + } + static func parse_notifyUsers(_ reader: BufferReader) -> NotifyPeer? { + return Api.NotifyPeer.notifyUsers + } + static func parse_notifyChats(_ reader: BufferReader) -> NotifyPeer? { + return Api.NotifyPeer.notifyChats + } + static func parse_notifyBroadcasts(_ reader: BufferReader) -> NotifyPeer? { + return Api.NotifyPeer.notifyBroadcasts + } + + } + enum InputPrivacyKey: TypeConstructorDescription { + case inputPrivacyKeyStatusTimestamp + case inputPrivacyKeyChatInvite + case inputPrivacyKeyPhoneCall + case inputPrivacyKeyPhoneP2P + case inputPrivacyKeyForwards + case inputPrivacyKeyProfilePhoto + case inputPrivacyKeyPhoneNumber + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPrivacyKeyStatusTimestamp: + if boxed { + buffer.appendInt32(1335282456) + } + + break + case .inputPrivacyKeyChatInvite: + if boxed { + buffer.appendInt32(-1107622874) + } + + break + case .inputPrivacyKeyPhoneCall: + if boxed { + buffer.appendInt32(-88417185) + } + + break + case .inputPrivacyKeyPhoneP2P: + if boxed { + buffer.appendInt32(-610373422) + } + + break + case .inputPrivacyKeyForwards: + if boxed { + buffer.appendInt32(-1529000952) + } + + break + case .inputPrivacyKeyProfilePhoto: + if boxed { + buffer.appendInt32(1461304012) + } + + break + case .inputPrivacyKeyPhoneNumber: + if boxed { + buffer.appendInt32(55761658) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPrivacyKeyStatusTimestamp: + return ("inputPrivacyKeyStatusTimestamp", []) + case .inputPrivacyKeyChatInvite: + return ("inputPrivacyKeyChatInvite", []) + case .inputPrivacyKeyPhoneCall: + return ("inputPrivacyKeyPhoneCall", []) + case .inputPrivacyKeyPhoneP2P: + return ("inputPrivacyKeyPhoneP2P", []) + case .inputPrivacyKeyForwards: + return ("inputPrivacyKeyForwards", []) + case .inputPrivacyKeyProfilePhoto: + return ("inputPrivacyKeyProfilePhoto", []) + case .inputPrivacyKeyPhoneNumber: + return ("inputPrivacyKeyPhoneNumber", []) + } + } + + static func parse_inputPrivacyKeyStatusTimestamp(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyStatusTimestamp + } + static func parse_inputPrivacyKeyChatInvite(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyChatInvite + } + static func parse_inputPrivacyKeyPhoneCall(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyPhoneCall + } + static func parse_inputPrivacyKeyPhoneP2P(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyPhoneP2P + } + static func parse_inputPrivacyKeyForwards(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyForwards + } + static func parse_inputPrivacyKeyProfilePhoto(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyProfilePhoto + } + static func parse_inputPrivacyKeyPhoneNumber(_ reader: BufferReader) -> InputPrivacyKey? { + return Api.InputPrivacyKey.inputPrivacyKeyPhoneNumber + } + + } + enum ReplyMarkup: TypeConstructorDescription { + case replyKeyboardHide(flags: Int32) + case replyKeyboardForceReply(flags: Int32) + case replyKeyboardMarkup(flags: Int32, rows: [Api.KeyboardButtonRow]) + case replyInlineMarkup(rows: [Api.KeyboardButtonRow]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .replyKeyboardHide(let flags): + if boxed { + buffer.appendInt32(-1606526075) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + case .replyKeyboardForceReply(let flags): + if boxed { + buffer.appendInt32(-200242528) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + case .replyKeyboardMarkup(let flags, let rows): + if boxed { + buffer.appendInt32(889353612) + } + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rows.count)) + for item in rows { + item.serialize(buffer, true) + } + break + case .replyInlineMarkup(let rows): + if boxed { + buffer.appendInt32(1218642516) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rows.count)) + for item in rows { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .replyKeyboardHide(let flags): + return ("replyKeyboardHide", [("flags", flags)]) + case .replyKeyboardForceReply(let flags): + return ("replyKeyboardForceReply", [("flags", flags)]) + case .replyKeyboardMarkup(let flags, let rows): + return ("replyKeyboardMarkup", [("flags", flags), ("rows", rows)]) + case .replyInlineMarkup(let rows): + return ("replyInlineMarkup", [("rows", rows)]) + } + } + + static func parse_replyKeyboardHide(_ reader: BufferReader) -> ReplyMarkup? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ReplyMarkup.replyKeyboardHide(flags: _1!) + } + else { + return nil + } + } + static func parse_replyKeyboardForceReply(_ reader: BufferReader) -> ReplyMarkup? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ReplyMarkup.replyKeyboardForceReply(flags: _1!) + } + else { + return nil + } + } + static func parse_replyKeyboardMarkup(_ reader: BufferReader) -> ReplyMarkup? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.KeyboardButtonRow]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.KeyboardButtonRow.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ReplyMarkup.replyKeyboardMarkup(flags: _1!, rows: _2!) + } + else { + return nil + } + } + static func parse_replyInlineMarkup(_ reader: BufferReader) -> ReplyMarkup? { + var _1: [Api.KeyboardButtonRow]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.KeyboardButtonRow.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.ReplyMarkup.replyInlineMarkup(rows: _1!) + } + else { + return nil + } + } + + } + enum EmojiKeywordsDifference: TypeConstructorDescription { + case emojiKeywordsDifference(langCode: String, fromVersion: Int32, version: Int32, keywords: [Api.EmojiKeyword]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .emojiKeywordsDifference(let langCode, let fromVersion, let version, let keywords): + if boxed { + buffer.appendInt32(1556570557) + } + serializeString(langCode, buffer: buffer, boxed: false) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(keywords.count)) + for item in keywords { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .emojiKeywordsDifference(let langCode, let fromVersion, let version, let keywords): + return ("emojiKeywordsDifference", [("langCode", langCode), ("fromVersion", fromVersion), ("version", version), ("keywords", keywords)]) + } + } + + static func parse_emojiKeywordsDifference(_ reader: BufferReader) -> EmojiKeywordsDifference? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: [Api.EmojiKeyword]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EmojiKeyword.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.EmojiKeywordsDifference.emojiKeywordsDifference(langCode: _1!, fromVersion: _2!, version: _3!, keywords: _4!) + } + else { + return nil + } + } + + } + enum HighScore: TypeConstructorDescription { + case highScore(pos: Int32, userId: Int32, score: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .highScore(let pos, let userId, let score): + if boxed { + buffer.appendInt32(1493171408) + } + serializeInt32(pos, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(score, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .highScore(let pos, let userId, let score): + return ("highScore", [("pos", pos), ("userId", userId), ("score", score)]) + } + } + + static func parse_highScore(_ reader: BufferReader) -> HighScore? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.HighScore.highScore(pos: _1!, userId: _2!, score: _3!) + } + else { + return nil + } + } + + } + enum TopPeer: TypeConstructorDescription { + case topPeer(peer: Api.Peer, rating: Double) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .topPeer(let peer, let rating): + if boxed { + buffer.appendInt32(-305282981) + } + peer.serialize(buffer, true) + serializeDouble(rating, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .topPeer(let peer, let rating): + return ("topPeer", [("peer", peer), ("rating", rating)]) + } + } + + static func parse_topPeer(_ reader: BufferReader) -> TopPeer? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.TopPeer.topPeer(peer: _1!, rating: _2!) + } + else { + return nil + } + } + + } + enum SecureValue: TypeConstructorDescription { + case secureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.SecureFile?, reverseSide: Api.SecureFile?, selfie: Api.SecureFile?, translation: [Api.SecureFile]?, files: [Api.SecureFile]?, plainData: Api.SecurePlainData?, hash: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData, let hash): + if boxed { + buffer.appendInt32(411017418) + } + serializeInt32(flags, buffer: buffer, boxed: false) + type.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {data!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {frontSide!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {reverseSide!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {selfie!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(translation!.count)) + for item in translation! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(files!.count)) + for item in files! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 5) != 0 {plainData!.serialize(buffer, true)} + serializeBytes(hash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData, let hash): + return ("secureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("translation", translation), ("files", files), ("plainData", plainData), ("hash", hash)]) + } + } + + static func parse_secureValue(_ reader: BufferReader) -> SecureValue? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureValueType? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _3: Api.SecureData? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.SecureData + } } + var _4: Api.SecureFile? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.SecureFile + } } + var _5: Api.SecureFile? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.SecureFile + } } + var _6: Api.SecureFile? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.SecureFile + } } + var _7: [Api.SecureFile]? + if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) + } } + var _8: [Api.SecureFile]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) + } } + var _9: Api.SecurePlainData? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.SecurePlainData + } } + var _10: Buffer? + _10 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.SecureValue.secureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, translation: _7, files: _8, plainData: _9, hash: _10!) + } + else { + return nil + } + } + + } + enum SecureValueHash: TypeConstructorDescription { + case secureValueHash(type: Api.SecureValueType, hash: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValueHash(let type, let hash): + if boxed { + buffer.appendInt32(-316748368) + } + type.serialize(buffer, true) + serializeBytes(hash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureValueHash(let type, let hash): + return ("secureValueHash", [("type", type), ("hash", hash)]) + } + } + + static func parse_secureValueHash(_ reader: BufferReader) -> SecureValueHash? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.SecureValueHash.secureValueHash(type: _1!, hash: _2!) + } + else { + return nil + } + } + + } + enum ContactBlocked: TypeConstructorDescription { + case contactBlocked(userId: Int32, date: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contactBlocked(let userId, let date): + if boxed { + buffer.appendInt32(1444661369) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contactBlocked(let userId, let date): + return ("contactBlocked", [("userId", userId), ("date", date)]) + } + } + + static func parse_contactBlocked(_ reader: BufferReader) -> ContactBlocked? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ContactBlocked.contactBlocked(userId: _1!, date: _2!) + } + else { + return nil + } + } + + } + enum PageListItem: TypeConstructorDescription { + case pageListItemText(text: Api.RichText) + case pageListItemBlocks(blocks: [Api.PageBlock]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageListItemText(let text): + if boxed { + buffer.appendInt32(-1188055347) + } + text.serialize(buffer, true) + break + case .pageListItemBlocks(let blocks): + if boxed { + buffer.appendInt32(635466748) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageListItemText(let text): + return ("pageListItemText", [("text", text)]) + case .pageListItemBlocks(let blocks): + return ("pageListItemBlocks", [("blocks", blocks)]) + } + } + + static func parse_pageListItemText(_ reader: BufferReader) -> PageListItem? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + if _c1 { + return Api.PageListItem.pageListItemText(text: _1!) + } + else { + return nil + } + } + static func parse_pageListItemBlocks(_ reader: BufferReader) -> PageListItem? { + var _1: [Api.PageBlock]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PageListItem.pageListItemBlocks(blocks: _1!) + } + else { + return nil + } + } + + } + enum InputUser: TypeConstructorDescription { + case inputUserEmpty + case inputUserSelf + case inputUser(userId: Int32, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputUserEmpty: + if boxed { + buffer.appendInt32(-1182234929) + } + + break + case .inputUserSelf: + if boxed { + buffer.appendInt32(-138301121) + } + + break + case .inputUser(let userId, let accessHash): + if boxed { + buffer.appendInt32(-668391402) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputUserEmpty: + return ("inputUserEmpty", []) + case .inputUserSelf: + return ("inputUserSelf", []) + case .inputUser(let userId, let accessHash): + return ("inputUser", [("userId", userId), ("accessHash", accessHash)]) + } + } + + static func parse_inputUserEmpty(_ reader: BufferReader) -> InputUser? { + return Api.InputUser.inputUserEmpty + } + static func parse_inputUserSelf(_ reader: BufferReader) -> InputUser? { + return Api.InputUser.inputUserSelf + } + static func parse_inputUser(_ reader: BufferReader) -> InputUser? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputUser.inputUser(userId: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum Page: TypeConstructorDescription { + case page(flags: Int32, url: String, blocks: [Api.PageBlock], photos: [Api.Photo], documents: [Api.Document]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .page(let flags, let url, let blocks, let photos, let documents): + if boxed { + buffer.appendInt32(-1366746132) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(documents.count)) + for item in documents { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .page(let flags, let url, let blocks, let photos, let documents): + return ("page", [("flags", flags), ("url", url), ("blocks", blocks), ("photos", photos), ("documents", documents)]) + } + } + + static func parse_page(_ reader: BufferReader) -> Page? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.PageBlock]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _4: [Api.Photo]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _5: [Api.Document]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.Page.page(flags: _1!, url: _2!, blocks: _3!, photos: _4!, documents: _5!) + } + else { + return nil + } + } + + } + enum SecureCredentialsEncrypted: TypeConstructorDescription { + case secureCredentialsEncrypted(data: Buffer, hash: Buffer, secret: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureCredentialsEncrypted(let data, let hash, let secret): + if boxed { + buffer.appendInt32(871426631) + } + serializeBytes(data, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + serializeBytes(secret, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureCredentialsEncrypted(let data, let hash, let secret): + return ("secureCredentialsEncrypted", [("data", data), ("hash", hash), ("secret", secret)]) + } + } + + static func parse_secureCredentialsEncrypted(_ reader: BufferReader) -> SecureCredentialsEncrypted? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureCredentialsEncrypted.secureCredentialsEncrypted(data: _1!, hash: _2!, secret: _3!) + } + else { + return nil + } + } + + } + enum MessageRange: TypeConstructorDescription { + case messageRange(minId: Int32, maxId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageRange(let minId, let maxId): + if boxed { + buffer.appendInt32(182649427) + } + serializeInt32(minId, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageRange(let minId, let maxId): + return ("messageRange", [("minId", minId), ("maxId", maxId)]) + } + } + + static func parse_messageRange(_ reader: BufferReader) -> MessageRange? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageRange.messageRange(minId: _1!, maxId: _2!) + } + else { + return nil + } + } + + } + enum Config: TypeConstructorDescription { + case config(flags: Int32, date: Int32, expires: Int32, testMode: Api.Bool, thisDc: Int32, dcOptions: [Api.DcOption], dcTxtDomainName: String, chatSizeMax: Int32, megagroupSizeMax: Int32, forwardedCountMax: Int32, onlineUpdatePeriodMs: Int32, offlineBlurTimeoutMs: Int32, offlineIdleTimeoutMs: Int32, onlineCloudTimeoutMs: Int32, notifyCloudDelayMs: Int32, notifyDefaultDelayMs: Int32, pushChatPeriodMs: Int32, pushChatLimit: Int32, savedGifsLimit: Int32, editTimeLimit: Int32, revokeTimeLimit: Int32, revokePmTimeLimit: Int32, ratingEDecay: Int32, stickersRecentLimit: Int32, stickersFavedLimit: Int32, channelsReadMediaPeriod: Int32, tmpSessions: Int32?, pinnedDialogsCountMax: Int32, pinnedInfolderCountMax: Int32, callReceiveTimeoutMs: Int32, callRingTimeoutMs: Int32, callConnectTimeoutMs: Int32, callPacketTimeoutMs: Int32, meUrlPrefix: String, autoupdateUrlPrefix: String?, gifSearchUsername: String?, venueSearchUsername: String?, imgSearchUsername: String?, staticMapsProvider: String?, captionLengthMax: Int32, messageLengthMax: Int32, webfileDcId: Int32, suggestedLangCode: String?, langPackVersion: Int32?, baseLangPackVersion: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let pinnedInfolderCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion, let baseLangPackVersion): + if boxed { + buffer.appendInt32(856375399) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(expires, buffer: buffer, boxed: false) + testMode.serialize(buffer, true) + serializeInt32(thisDc, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dcOptions.count)) + for item in dcOptions { + item.serialize(buffer, true) + } + serializeString(dcTxtDomainName, buffer: buffer, boxed: false) + serializeInt32(chatSizeMax, buffer: buffer, boxed: false) + serializeInt32(megagroupSizeMax, buffer: buffer, boxed: false) + serializeInt32(forwardedCountMax, buffer: buffer, boxed: false) + serializeInt32(onlineUpdatePeriodMs, buffer: buffer, boxed: false) + serializeInt32(offlineBlurTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(offlineIdleTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(onlineCloudTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(notifyCloudDelayMs, buffer: buffer, boxed: false) + serializeInt32(notifyDefaultDelayMs, buffer: buffer, boxed: false) + serializeInt32(pushChatPeriodMs, buffer: buffer, boxed: false) + serializeInt32(pushChatLimit, buffer: buffer, boxed: false) + serializeInt32(savedGifsLimit, buffer: buffer, boxed: false) + serializeInt32(editTimeLimit, buffer: buffer, boxed: false) + serializeInt32(revokeTimeLimit, buffer: buffer, boxed: false) + serializeInt32(revokePmTimeLimit, buffer: buffer, boxed: false) + serializeInt32(ratingEDecay, buffer: buffer, boxed: false) + serializeInt32(stickersRecentLimit, buffer: buffer, boxed: false) + serializeInt32(stickersFavedLimit, buffer: buffer, boxed: false) + serializeInt32(channelsReadMediaPeriod, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(tmpSessions!, buffer: buffer, boxed: false)} + serializeInt32(pinnedDialogsCountMax, buffer: buffer, boxed: false) + serializeInt32(pinnedInfolderCountMax, buffer: buffer, boxed: false) + serializeInt32(callReceiveTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(callRingTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(callConnectTimeoutMs, buffer: buffer, boxed: false) + serializeInt32(callPacketTimeoutMs, buffer: buffer, boxed: false) + serializeString(meUrlPrefix, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 7) != 0 {serializeString(autoupdateUrlPrefix!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 9) != 0 {serializeString(gifSearchUsername!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 10) != 0 {serializeString(venueSearchUsername!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 11) != 0 {serializeString(imgSearchUsername!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 12) != 0 {serializeString(staticMapsProvider!, buffer: buffer, boxed: false)} + serializeInt32(captionLengthMax, buffer: buffer, boxed: false) + serializeInt32(messageLengthMax, buffer: buffer, boxed: false) + serializeInt32(webfileDcId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {serializeString(suggestedLangCode!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(langPackVersion!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(baseLangPackVersion!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .config(let flags, let date, let expires, let testMode, let thisDc, let dcOptions, let dcTxtDomainName, let chatSizeMax, let megagroupSizeMax, let forwardedCountMax, let onlineUpdatePeriodMs, let offlineBlurTimeoutMs, let offlineIdleTimeoutMs, let onlineCloudTimeoutMs, let notifyCloudDelayMs, let notifyDefaultDelayMs, let pushChatPeriodMs, let pushChatLimit, let savedGifsLimit, let editTimeLimit, let revokeTimeLimit, let revokePmTimeLimit, let ratingEDecay, let stickersRecentLimit, let stickersFavedLimit, let channelsReadMediaPeriod, let tmpSessions, let pinnedDialogsCountMax, let pinnedInfolderCountMax, let callReceiveTimeoutMs, let callRingTimeoutMs, let callConnectTimeoutMs, let callPacketTimeoutMs, let meUrlPrefix, let autoupdateUrlPrefix, let gifSearchUsername, let venueSearchUsername, let imgSearchUsername, let staticMapsProvider, let captionLengthMax, let messageLengthMax, let webfileDcId, let suggestedLangCode, let langPackVersion, let baseLangPackVersion): + return ("config", [("flags", flags), ("date", date), ("expires", expires), ("testMode", testMode), ("thisDc", thisDc), ("dcOptions", dcOptions), ("dcTxtDomainName", dcTxtDomainName), ("chatSizeMax", chatSizeMax), ("megagroupSizeMax", megagroupSizeMax), ("forwardedCountMax", forwardedCountMax), ("onlineUpdatePeriodMs", onlineUpdatePeriodMs), ("offlineBlurTimeoutMs", offlineBlurTimeoutMs), ("offlineIdleTimeoutMs", offlineIdleTimeoutMs), ("onlineCloudTimeoutMs", onlineCloudTimeoutMs), ("notifyCloudDelayMs", notifyCloudDelayMs), ("notifyDefaultDelayMs", notifyDefaultDelayMs), ("pushChatPeriodMs", pushChatPeriodMs), ("pushChatLimit", pushChatLimit), ("savedGifsLimit", savedGifsLimit), ("editTimeLimit", editTimeLimit), ("revokeTimeLimit", revokeTimeLimit), ("revokePmTimeLimit", revokePmTimeLimit), ("ratingEDecay", ratingEDecay), ("stickersRecentLimit", stickersRecentLimit), ("stickersFavedLimit", stickersFavedLimit), ("channelsReadMediaPeriod", channelsReadMediaPeriod), ("tmpSessions", tmpSessions), ("pinnedDialogsCountMax", pinnedDialogsCountMax), ("pinnedInfolderCountMax", pinnedInfolderCountMax), ("callReceiveTimeoutMs", callReceiveTimeoutMs), ("callRingTimeoutMs", callRingTimeoutMs), ("callConnectTimeoutMs", callConnectTimeoutMs), ("callPacketTimeoutMs", callPacketTimeoutMs), ("meUrlPrefix", meUrlPrefix), ("autoupdateUrlPrefix", autoupdateUrlPrefix), ("gifSearchUsername", gifSearchUsername), ("venueSearchUsername", venueSearchUsername), ("imgSearchUsername", imgSearchUsername), ("staticMapsProvider", staticMapsProvider), ("captionLengthMax", captionLengthMax), ("messageLengthMax", messageLengthMax), ("webfileDcId", webfileDcId), ("suggestedLangCode", suggestedLangCode), ("langPackVersion", langPackVersion), ("baseLangPackVersion", baseLangPackVersion)]) + } + } + + static func parse_config(_ reader: BufferReader) -> Config? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Api.Bool? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Bool + } + var _5: Int32? + _5 = reader.readInt32() + var _6: [Api.DcOption]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DcOption.self) + } + var _7: String? + _7 = parseString(reader) + var _8: Int32? + _8 = reader.readInt32() + var _9: Int32? + _9 = reader.readInt32() + var _10: Int32? + _10 = reader.readInt32() + var _11: Int32? + _11 = reader.readInt32() + var _12: Int32? + _12 = reader.readInt32() + var _13: Int32? + _13 = reader.readInt32() + var _14: Int32? + _14 = reader.readInt32() + var _15: Int32? + _15 = reader.readInt32() + var _16: Int32? + _16 = reader.readInt32() + var _17: Int32? + _17 = reader.readInt32() + var _18: Int32? + _18 = reader.readInt32() + var _19: Int32? + _19 = reader.readInt32() + var _20: Int32? + _20 = reader.readInt32() + var _21: Int32? + _21 = reader.readInt32() + var _22: Int32? + _22 = reader.readInt32() + var _23: Int32? + _23 = reader.readInt32() + var _24: Int32? + _24 = reader.readInt32() + var _25: Int32? + _25 = reader.readInt32() + var _26: Int32? + _26 = reader.readInt32() + var _27: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_27 = reader.readInt32() } + var _28: Int32? + _28 = reader.readInt32() + var _29: Int32? + _29 = reader.readInt32() + var _30: Int32? + _30 = reader.readInt32() + var _31: Int32? + _31 = reader.readInt32() + var _32: Int32? + _32 = reader.readInt32() + var _33: Int32? + _33 = reader.readInt32() + var _34: String? + _34 = parseString(reader) + var _35: String? + if Int(_1!) & Int(1 << 7) != 0 {_35 = parseString(reader) } + var _36: String? + if Int(_1!) & Int(1 << 9) != 0 {_36 = parseString(reader) } + var _37: String? + if Int(_1!) & Int(1 << 10) != 0 {_37 = parseString(reader) } + var _38: String? + if Int(_1!) & Int(1 << 11) != 0 {_38 = parseString(reader) } + var _39: String? + if Int(_1!) & Int(1 << 12) != 0 {_39 = parseString(reader) } + var _40: Int32? + _40 = reader.readInt32() + var _41: Int32? + _41 = reader.readInt32() + var _42: Int32? + _42 = reader.readInt32() + var _43: String? + if Int(_1!) & Int(1 << 2) != 0 {_43 = parseString(reader) } + var _44: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_44 = reader.readInt32() } + var _45: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_45 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + let _c16 = _16 != nil + let _c17 = _17 != nil + let _c18 = _18 != nil + let _c19 = _19 != nil + let _c20 = _20 != nil + let _c21 = _21 != nil + let _c22 = _22 != nil + let _c23 = _23 != nil + let _c24 = _24 != nil + let _c25 = _25 != nil + let _c26 = _26 != nil + let _c27 = (Int(_1!) & Int(1 << 0) == 0) || _27 != nil + let _c28 = _28 != nil + let _c29 = _29 != nil + let _c30 = _30 != nil + let _c31 = _31 != nil + let _c32 = _32 != nil + let _c33 = _33 != nil + let _c34 = _34 != nil + let _c35 = (Int(_1!) & Int(1 << 7) == 0) || _35 != nil + let _c36 = (Int(_1!) & Int(1 << 9) == 0) || _36 != nil + let _c37 = (Int(_1!) & Int(1 << 10) == 0) || _37 != nil + let _c38 = (Int(_1!) & Int(1 << 11) == 0) || _38 != nil + let _c39 = (Int(_1!) & Int(1 << 12) == 0) || _39 != nil + let _c40 = _40 != nil + let _c41 = _41 != nil + let _c42 = _42 != nil + let _c43 = (Int(_1!) & Int(1 << 2) == 0) || _43 != nil + let _c44 = (Int(_1!) & Int(1 << 2) == 0) || _44 != nil + let _c45 = (Int(_1!) & Int(1 << 2) == 0) || _45 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 && _c40 && _c41 && _c42 && _c43 && _c44 && _c45 { + return Api.Config.config(flags: _1!, date: _2!, expires: _3!, testMode: _4!, thisDc: _5!, dcOptions: _6!, dcTxtDomainName: _7!, chatSizeMax: _8!, megagroupSizeMax: _9!, forwardedCountMax: _10!, onlineUpdatePeriodMs: _11!, offlineBlurTimeoutMs: _12!, offlineIdleTimeoutMs: _13!, onlineCloudTimeoutMs: _14!, notifyCloudDelayMs: _15!, notifyDefaultDelayMs: _16!, pushChatPeriodMs: _17!, pushChatLimit: _18!, savedGifsLimit: _19!, editTimeLimit: _20!, revokeTimeLimit: _21!, revokePmTimeLimit: _22!, ratingEDecay: _23!, stickersRecentLimit: _24!, stickersFavedLimit: _25!, channelsReadMediaPeriod: _26!, tmpSessions: _27, pinnedDialogsCountMax: _28!, pinnedInfolderCountMax: _29!, callReceiveTimeoutMs: _30!, callRingTimeoutMs: _31!, callConnectTimeoutMs: _32!, callPacketTimeoutMs: _33!, meUrlPrefix: _34!, autoupdateUrlPrefix: _35, gifSearchUsername: _36, venueSearchUsername: _37, imgSearchUsername: _38, staticMapsProvider: _39, captionLengthMax: _40!, messageLengthMax: _41!, webfileDcId: _42!, suggestedLangCode: _43, langPackVersion: _44, baseLangPackVersion: _45) + } + else { + return nil + } + } + + } + enum TopPeerCategoryPeers: TypeConstructorDescription { + case topPeerCategoryPeers(category: Api.TopPeerCategory, count: Int32, peers: [Api.TopPeer]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .topPeerCategoryPeers(let category, let count, let peers): + if boxed { + buffer.appendInt32(-75283823) + } + category.serialize(buffer, true) + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(peers.count)) + for item in peers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .topPeerCategoryPeers(let category, let count, let peers): + return ("topPeerCategoryPeers", [("category", category), ("count", count), ("peers", peers)]) + } + } + + static func parse_topPeerCategoryPeers(_ reader: BufferReader) -> TopPeerCategoryPeers? { + var _1: Api.TopPeerCategory? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.TopPeerCategory + } + var _2: Int32? + _2 = reader.readInt32() + var _3: [Api.TopPeer]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.TopPeer.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.TopPeerCategoryPeers.topPeerCategoryPeers(category: _1!, count: _2!, peers: _3!) + } + else { + return nil + } + } + + } + enum Game: TypeConstructorDescription { + case game(flags: Int32, id: Int64, accessHash: Int64, shortName: String, title: String, description: String, photo: Api.Photo, document: Api.Document?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document): + if boxed { + buffer.appendInt32(-1107729093) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeString(shortName, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document): + return ("game", [("flags", flags), ("id", id), ("accessHash", accessHash), ("shortName", shortName), ("title", title), ("description", description), ("photo", photo), ("document", document)]) + } + } + + static func parse_game(_ reader: BufferReader) -> Game? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + var _7: Api.Photo? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _8: Api.Document? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.Document + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.Game.game(flags: _1!, id: _2!, accessHash: _3!, shortName: _4!, title: _5!, description: _6!, photo: _7!, document: _8) + } + else { + return nil + } + } + + } + enum ChatAdminRights: TypeConstructorDescription { + case chatAdminRights(flags: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatAdminRights(let flags): + if boxed { + buffer.appendInt32(1605510357) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatAdminRights(let flags): + return ("chatAdminRights", [("flags", flags)]) + } + } + + static func parse_chatAdminRights(_ reader: BufferReader) -> ChatAdminRights? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ChatAdminRights.chatAdminRights(flags: _1!) + } + else { + return nil + } + } + + } + enum SecurePasswordKdfAlgo: TypeConstructorDescription { + case securePasswordKdfAlgoUnknown + case securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt: Buffer) + case securePasswordKdfAlgoSHA512(salt: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .securePasswordKdfAlgoUnknown: + if boxed { + buffer.appendInt32(4883767) + } + + break + case .securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(let salt): + if boxed { + buffer.appendInt32(-1141711456) + } + serializeBytes(salt, buffer: buffer, boxed: false) + break + case .securePasswordKdfAlgoSHA512(let salt): + if boxed { + buffer.appendInt32(-2042159726) + } + serializeBytes(salt, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .securePasswordKdfAlgoUnknown: + return ("securePasswordKdfAlgoUnknown", []) + case .securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(let salt): + return ("securePasswordKdfAlgoPBKDF2HMACSHA512iter100000", [("salt", salt)]) + case .securePasswordKdfAlgoSHA512(let salt): + return ("securePasswordKdfAlgoSHA512", [("salt", salt)]) + } + } + + static func parse_securePasswordKdfAlgoUnknown(_ reader: BufferReader) -> SecurePasswordKdfAlgo? { + return Api.SecurePasswordKdfAlgo.securePasswordKdfAlgoUnknown + } + static func parse_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(_ reader: BufferReader) -> SecurePasswordKdfAlgo? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.SecurePasswordKdfAlgo.securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt: _1!) + } + else { + return nil + } + } + static func parse_securePasswordKdfAlgoSHA512(_ reader: BufferReader) -> SecurePasswordKdfAlgo? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.SecurePasswordKdfAlgo.securePasswordKdfAlgoSHA512(salt: _1!) + } + else { + return nil + } + } + + } + enum BotCommand: TypeConstructorDescription { + case botCommand(command: String, description: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botCommand(let command, let description): + if boxed { + buffer.appendInt32(-1032140601) + } + serializeString(command, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botCommand(let command, let description): + return ("botCommand", [("command", command), ("description", description)]) + } + } + + static func parse_botCommand(_ reader: BufferReader) -> BotCommand? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BotCommand.botCommand(command: _1!, description: _2!) + } + else { + return nil + } + } + + } + enum CdnPublicKey: TypeConstructorDescription { + case cdnPublicKey(dcId: Int32, publicKey: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .cdnPublicKey(let dcId, let publicKey): + if boxed { + buffer.appendInt32(-914167110) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeString(publicKey, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .cdnPublicKey(let dcId, let publicKey): + return ("cdnPublicKey", [("dcId", dcId), ("publicKey", publicKey)]) + } + } + + static func parse_cdnPublicKey(_ reader: BufferReader) -> CdnPublicKey? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.CdnPublicKey.cdnPublicKey(dcId: _1!, publicKey: _2!) + } + else { + return nil + } + } + + } + enum InputGame: TypeConstructorDescription { + case inputGameID(id: Int64, accessHash: Int64) + case inputGameShortName(botId: Api.InputUser, shortName: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputGameID(let id, let accessHash): + if boxed { + buffer.appendInt32(53231223) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputGameShortName(let botId, let shortName): + if boxed { + buffer.appendInt32(-1020139510) + } + botId.serialize(buffer, true) + serializeString(shortName, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputGameID(let id, let accessHash): + return ("inputGameID", [("id", id), ("accessHash", accessHash)]) + case .inputGameShortName(let botId, let shortName): + return ("inputGameShortName", [("botId", botId), ("shortName", shortName)]) + } + } + + static func parse_inputGameID(_ reader: BufferReader) -> InputGame? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputGame.inputGameID(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputGameShortName(_ reader: BufferReader) -> InputGame? { + var _1: Api.InputUser? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputUser + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputGame.inputGameShortName(botId: _1!, shortName: _2!) + } + else { + return nil + } + } + + } + enum InputMessage: TypeConstructorDescription { + case inputMessageID(id: Int32) + case inputMessageReplyTo(id: Int32) + case inputMessagePinned + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputMessageID(let id): + if boxed { + buffer.appendInt32(-1502174430) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .inputMessageReplyTo(let id): + if boxed { + buffer.appendInt32(-1160215659) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .inputMessagePinned: + if boxed { + buffer.appendInt32(-2037963464) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputMessageID(let id): + return ("inputMessageID", [("id", id)]) + case .inputMessageReplyTo(let id): + return ("inputMessageReplyTo", [("id", id)]) + case .inputMessagePinned: + return ("inputMessagePinned", []) + } + } + + static func parse_inputMessageID(_ reader: BufferReader) -> InputMessage? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.InputMessage.inputMessageID(id: _1!) + } + else { + return nil + } + } + static func parse_inputMessageReplyTo(_ reader: BufferReader) -> InputMessage? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.InputMessage.inputMessageReplyTo(id: _1!) + } + else { + return nil + } + } + static func parse_inputMessagePinned(_ reader: BufferReader) -> InputMessage? { + return Api.InputMessage.inputMessagePinned + } + + } + enum PhoneCallProtocol: TypeConstructorDescription { + case phoneCallProtocol(flags: Int32, minLayer: Int32, maxLayer: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .phoneCallProtocol(let flags, let minLayer, let maxLayer): + if boxed { + buffer.appendInt32(-1564789301) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(minLayer, buffer: buffer, boxed: false) + serializeInt32(maxLayer, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .phoneCallProtocol(let flags, let minLayer, let maxLayer): + return ("phoneCallProtocol", [("flags", flags), ("minLayer", minLayer), ("maxLayer", maxLayer)]) + } + } + + static func parse_phoneCallProtocol(_ reader: BufferReader) -> PhoneCallProtocol? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.PhoneCallProtocol.phoneCallProtocol(flags: _1!, minLayer: _2!, maxLayer: _3!) + } + else { + return nil + } + } + + } + enum MessageFwdAuthor: TypeConstructorDescription { + case messageFwdAuthor(channelId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageFwdAuthor(let channelId): + if boxed { + buffer.appendInt32(-1567175714) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageFwdAuthor(let channelId): + return ("messageFwdAuthor", [("channelId", channelId)]) + } + } + + static func parse_messageFwdAuthor(_ reader: BufferReader) -> MessageFwdAuthor? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessageFwdAuthor.messageFwdAuthor(channelId: _1!) + } + else { + return nil + } + } + + } + enum WallPaper: TypeConstructorDescription { + case wallPaper(id: Int64, flags: Int32, accessHash: Int64, slug: String, document: Api.Document, settings: Api.WallPaperSettings?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .wallPaper(let id, let flags, let accessHash, let slug, let document, let settings): + if boxed { + buffer.appendInt32(-1539849235) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeString(slug, buffer: buffer, boxed: false) + document.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {settings!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .wallPaper(let id, let flags, let accessHash, let slug, let document, let settings): + return ("wallPaper", [("id", id), ("flags", flags), ("accessHash", accessHash), ("slug", slug), ("document", document), ("settings", settings)]) + } + } + + static func parse_wallPaper(_ reader: BufferReader) -> WallPaper? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + _4 = parseString(reader) + var _5: Api.Document? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document + } + var _6: Api.WallPaperSettings? + if Int(_2!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.WallPaperSettings + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_2!) & Int(1 << 2) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.WallPaper.wallPaper(id: _1!, flags: _2!, accessHash: _3!, slug: _4!, document: _5!, settings: _6) + } + else { + return nil + } + } + + } + enum Invoice: TypeConstructorDescription { + case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .invoice(let flags, let currency, let prices): + if boxed { + buffer.appendInt32(-1022713000) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(currency, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(prices.count)) + for item in prices { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .invoice(let flags, let currency, let prices): + return ("invoice", [("flags", flags), ("currency", currency), ("prices", prices)]) + } + } + + static func parse_invoice(_ reader: BufferReader) -> Invoice? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.LabeledPrice]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LabeledPrice.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!) + } + else { + return nil + } + } + + } + enum PeerSettings: TypeConstructorDescription { + case peerSettings(flags: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .peerSettings(let flags): + if boxed { + buffer.appendInt32(-2122045747) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .peerSettings(let flags): + return ("peerSettings", [("flags", flags)]) + } + } + + static func parse_peerSettings(_ reader: BufferReader) -> PeerSettings? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.PeerSettings.peerSettings(flags: _1!) + } + else { + return nil + } + } + + } + enum InputChatPhoto: TypeConstructorDescription { + case inputChatPhotoEmpty + case inputChatUploadedPhoto(file: Api.InputFile) + case inputChatPhoto(id: Api.InputPhoto) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputChatPhotoEmpty: + if boxed { + buffer.appendInt32(480546647) + } + + break + case .inputChatUploadedPhoto(let file): + if boxed { + buffer.appendInt32(-1837345356) + } + file.serialize(buffer, true) + break + case .inputChatPhoto(let id): + if boxed { + buffer.appendInt32(-1991004873) + } + id.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputChatPhotoEmpty: + return ("inputChatPhotoEmpty", []) + case .inputChatUploadedPhoto(let file): + return ("inputChatUploadedPhoto", [("file", file)]) + case .inputChatPhoto(let id): + return ("inputChatPhoto", [("id", id)]) + } + } + + static func parse_inputChatPhotoEmpty(_ reader: BufferReader) -> InputChatPhoto? { + return Api.InputChatPhoto.inputChatPhotoEmpty + } + static func parse_inputChatUploadedPhoto(_ reader: BufferReader) -> InputChatPhoto? { + var _1: Api.InputFile? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputFile + } + let _c1 = _1 != nil + if _c1 { + return Api.InputChatPhoto.inputChatUploadedPhoto(file: _1!) + } + else { + return nil + } + } + static func parse_inputChatPhoto(_ reader: BufferReader) -> InputChatPhoto? { + var _1: Api.InputPhoto? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPhoto + } + let _c1 = _1 != nil + if _c1 { + return Api.InputChatPhoto.inputChatPhoto(id: _1!) + } + else { + return nil + } + } + + } + enum PaymentCharge: TypeConstructorDescription { + case paymentCharge(id: String, providerChargeId: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentCharge(let id, let providerChargeId): + if boxed { + buffer.appendInt32(-368917890) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(providerChargeId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentCharge(let id, let providerChargeId): + return ("paymentCharge", [("id", id), ("providerChargeId", providerChargeId)]) + } + } + + static func parse_paymentCharge(_ reader: BufferReader) -> PaymentCharge? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PaymentCharge.paymentCharge(id: _1!, providerChargeId: _2!) + } + else { + return nil + } + } + + } + enum Updates: TypeConstructorDescription { + case updatesTooLong + case updateShortMessage(flags: Int32, id: Int32, userId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, entities: [Api.MessageEntity]?) + case updateShortChatMessage(flags: Int32, id: Int32, fromId: Int32, chatId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, entities: [Api.MessageEntity]?) + case updateShort(update: Api.Update, date: Int32) + case updatesCombined(updates: [Api.Update], users: [Api.User], chats: [Api.Chat], date: Int32, seqStart: Int32, seq: Int32) + case updates(updates: [Api.Update], users: [Api.User], chats: [Api.Chat], date: Int32, seq: Int32) + case updateShortSentMessage(flags: Int32, id: Int32, pts: Int32, ptsCount: Int32, date: Int32, media: Api.MessageMedia?, entities: [Api.MessageEntity]?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .updatesTooLong: + if boxed { + buffer.appendInt32(-484987010) + } + + break + case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyToMsgId, let entities): + if boxed { + buffer.appendInt32(-1857044719) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {fwdFrom!.serialize(buffer, true)} + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(viaBotId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyToMsgId, let entities): + if boxed { + buffer.appendInt32(377562760) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(fromId, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {fwdFrom!.serialize(buffer, true)} + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(viaBotId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + case .updateShort(let update, let date): + if boxed { + buffer.appendInt32(2027216577) + } + update.serialize(buffer, true) + serializeInt32(date, buffer: buffer, boxed: false) + break + case .updatesCombined(let updates, let users, let chats, let date, let seqStart, let seq): + if boxed { + buffer.appendInt32(1918567619) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(updates.count)) + for item in updates { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seqStart, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + break + case .updates(let updates, let users, let chats, let date, let seq): + if boxed { + buffer.appendInt32(1957577280) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(updates.count)) + for item in updates { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + break + case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities): + if boxed { + buffer.appendInt32(301019932) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(ptsCount, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .updatesTooLong: + return ("updatesTooLong", []) + case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyToMsgId, let entities): + return ("updateShortMessage", [("flags", flags), ("id", id), ("userId", userId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("entities", entities)]) + case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyToMsgId, let entities): + return ("updateShortChatMessage", [("flags", flags), ("id", id), ("fromId", fromId), ("chatId", chatId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("entities", entities)]) + case .updateShort(let update, let date): + return ("updateShort", [("update", update), ("date", date)]) + case .updatesCombined(let updates, let users, let chats, let date, let seqStart, let seq): + return ("updatesCombined", [("updates", updates), ("users", users), ("chats", chats), ("date", date), ("seqStart", seqStart), ("seq", seq)]) + case .updates(let updates, let users, let chats, let date, let seq): + return ("updates", [("updates", updates), ("users", users), ("chats", chats), ("date", date), ("seq", seq)]) + case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities): + return ("updateShortSentMessage", [("flags", flags), ("id", id), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("media", media), ("entities", entities)]) + } + } + + static func parse_updatesTooLong(_ reader: BufferReader) -> Updates? { + return Api.Updates.updatesTooLong + } + static func parse_updateShortMessage(_ reader: BufferReader) -> Updates? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Api.MessageFwdHeader? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader + } } + var _9: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_9 = reader.readInt32() } + var _10: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_10 = reader.readInt32() } + var _11: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 11) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 3) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return Api.Updates.updateShortMessage(flags: _1!, id: _2!, userId: _3!, message: _4!, pts: _5!, ptsCount: _6!, date: _7!, fwdFrom: _8, viaBotId: _9, replyToMsgId: _10, entities: _11) + } + else { + return nil + } + } + static func parse_updateShortChatMessage(_ reader: BufferReader) -> Updates? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + var _9: Api.MessageFwdHeader? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader + } } + var _10: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() } + var _11: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_11 = reader.readInt32() } + var _12: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = (Int(_1!) & Int(1 << 2) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil + let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 { + return Api.Updates.updateShortChatMessage(flags: _1!, id: _2!, fromId: _3!, chatId: _4!, message: _5!, pts: _6!, ptsCount: _7!, date: _8!, fwdFrom: _9, viaBotId: _10, replyToMsgId: _11, entities: _12) + } + else { + return nil + } + } + static func parse_updateShort(_ reader: BufferReader) -> Updates? { + var _1: Api.Update? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Update + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Updates.updateShort(update: _1!, date: _2!) + } + else { + return nil + } + } + static func parse_updatesCombined(_ reader: BufferReader) -> Updates? { + var _1: [Api.Update]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Updates.updatesCombined(updates: _1!, users: _2!, chats: _3!, date: _4!, seqStart: _5!, seq: _6!) + } + else { + return nil + } + } + static func parse_updates(_ reader: BufferReader) -> Updates? { + var _1: [Api.Update]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.Updates.updates(updates: _1!, users: _2!, chats: _3!, date: _4!, seq: _5!) + } + else { + return nil + } + } + static func parse_updateShortSentMessage(_ reader: BufferReader) -> Updates? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Api.MessageMedia? + if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.MessageMedia + } } + var _7: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 9) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 7) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.Updates.updateShortSentMessage(flags: _1!, id: _2!, pts: _3!, ptsCount: _4!, date: _5!, media: _6, entities: _7) + } + else { + return nil + } + } + + } + enum MessageMedia: TypeConstructorDescription { + case messageMediaEmpty + case messageMediaGeo(geo: Api.GeoPoint) + case messageMediaUnsupported + case messageMediaWebPage(webpage: Api.WebPage) + case messageMediaGame(game: Api.Game) + case messageMediaInvoice(flags: Int32, title: String, description: String, photo: Api.WebDocument?, receiptMsgId: Int32?, currency: String, totalAmount: Int64, startParam: String) + case messageMediaGeoLive(geo: Api.GeoPoint, period: Int32) + case messageMediaVenue(geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String) + case messageMediaPhoto(flags: Int32, photo: Api.Photo?, ttlSeconds: Int32?) + case messageMediaDocument(flags: Int32, document: Api.Document?, ttlSeconds: Int32?) + case messageMediaContact(phoneNumber: String, firstName: String, lastName: String, vcard: String, userId: Int32) + case messageMediaPoll(poll: Api.Poll, results: Api.PollResults) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageMediaEmpty: + if boxed { + buffer.appendInt32(1038967584) + } + + break + case .messageMediaGeo(let geo): + if boxed { + buffer.appendInt32(1457575028) + } + geo.serialize(buffer, true) + break + case .messageMediaUnsupported: + if boxed { + buffer.appendInt32(-1618676578) + } + + break + case .messageMediaWebPage(let webpage): + if boxed { + buffer.appendInt32(-1557277184) + } + webpage.serialize(buffer, true) + break + case .messageMediaGame(let game): + if boxed { + buffer.appendInt32(-38694904) + } + game.serialize(buffer, true) + break + case .messageMediaInvoice(let flags, let title, let description, let photo, let receiptMsgId, let currency, let totalAmount, let startParam): + if boxed { + buffer.appendInt32(-2074799289) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(receiptMsgId!, buffer: buffer, boxed: false)} + serializeString(currency, buffer: buffer, boxed: false) + serializeInt64(totalAmount, buffer: buffer, boxed: false) + serializeString(startParam, buffer: buffer, boxed: false) + break + case .messageMediaGeoLive(let geo, let period): + if boxed { + buffer.appendInt32(2084316681) + } + geo.serialize(buffer, true) + serializeInt32(period, buffer: buffer, boxed: false) + break + case .messageMediaVenue(let geo, let title, let address, let provider, let venueId, let venueType): + if boxed { + buffer.appendInt32(784356159) + } + geo.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + serializeString(venueType, buffer: buffer, boxed: false) + break + case .messageMediaPhoto(let flags, let photo, let ttlSeconds): + if boxed { + buffer.appendInt32(1766936791) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .messageMediaDocument(let flags, let document, let ttlSeconds): + if boxed { + buffer.appendInt32(-1666158377) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)} + break + case .messageMediaContact(let phoneNumber, let firstName, let lastName, let vcard, let userId): + if boxed { + buffer.appendInt32(-873313984) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(vcard, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .messageMediaPoll(let poll, let results): + if boxed { + buffer.appendInt32(1272375192) + } + poll.serialize(buffer, true) + results.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageMediaEmpty: + return ("messageMediaEmpty", []) + case .messageMediaGeo(let geo): + return ("messageMediaGeo", [("geo", geo)]) + case .messageMediaUnsupported: + return ("messageMediaUnsupported", []) + case .messageMediaWebPage(let webpage): + return ("messageMediaWebPage", [("webpage", webpage)]) + case .messageMediaGame(let game): + return ("messageMediaGame", [("game", game)]) + case .messageMediaInvoice(let flags, let title, let description, let photo, let receiptMsgId, let currency, let totalAmount, let startParam): + return ("messageMediaInvoice", [("flags", flags), ("title", title), ("description", description), ("photo", photo), ("receiptMsgId", receiptMsgId), ("currency", currency), ("totalAmount", totalAmount), ("startParam", startParam)]) + case .messageMediaGeoLive(let geo, let period): + return ("messageMediaGeoLive", [("geo", geo), ("period", period)]) + case .messageMediaVenue(let geo, let title, let address, let provider, let venueId, let venueType): + return ("messageMediaVenue", [("geo", geo), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType)]) + case .messageMediaPhoto(let flags, let photo, let ttlSeconds): + return ("messageMediaPhoto", [("flags", flags), ("photo", photo), ("ttlSeconds", ttlSeconds)]) + case .messageMediaDocument(let flags, let document, let ttlSeconds): + return ("messageMediaDocument", [("flags", flags), ("document", document), ("ttlSeconds", ttlSeconds)]) + case .messageMediaContact(let phoneNumber, let firstName, let lastName, let vcard, let userId): + return ("messageMediaContact", [("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("userId", userId)]) + case .messageMediaPoll(let poll, let results): + return ("messageMediaPoll", [("poll", poll), ("results", results)]) + } + } + + static func parse_messageMediaEmpty(_ reader: BufferReader) -> MessageMedia? { + return Api.MessageMedia.messageMediaEmpty + } + static func parse_messageMediaGeo(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.GeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageMedia.messageMediaGeo(geo: _1!) + } + else { + return nil + } + } + static func parse_messageMediaUnsupported(_ reader: BufferReader) -> MessageMedia? { + return Api.MessageMedia.messageMediaUnsupported + } + static func parse_messageMediaWebPage(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.WebPage? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.WebPage + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageMedia.messageMediaWebPage(webpage: _1!) + } + else { + return nil + } + } + static func parse_messageMediaGame(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.Game? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Game + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageMedia.messageMediaGame(game: _1!) + } + else { + return nil + } + } + static func parse_messageMediaInvoice(_ reader: BufferReader) -> MessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.WebDocument? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.WebDocument + } } + var _5: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_5 = reader.readInt32() } + var _6: String? + _6 = parseString(reader) + var _7: Int64? + _7 = reader.readInt64() + var _8: String? + _8 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.MessageMedia.messageMediaInvoice(flags: _1!, title: _2!, description: _3!, photo: _4, receiptMsgId: _5, currency: _6!, totalAmount: _7!, startParam: _8!) + } + else { + return nil + } + } + static func parse_messageMediaGeoLive(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.GeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageMedia.messageMediaGeoLive(geo: _1!, period: _2!) + } + else { + return nil + } + } + static func parse_messageMediaVenue(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.GeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.MessageMedia.messageMediaVenue(geo: _1!, title: _2!, address: _3!, provider: _4!, venueId: _5!, venueType: _6!) + } + else { + return nil + } + } + static func parse_messageMediaPhoto(_ reader: BufferReader) -> MessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Photo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _3: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageMedia.messageMediaPhoto(flags: _1!, photo: _2, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_messageMediaDocument(_ reader: BufferReader) -> MessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Document? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _3: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageMedia.messageMediaDocument(flags: _1!, document: _2, ttlSeconds: _3) + } + else { + return nil + } + } + static func parse_messageMediaContact(_ reader: BufferReader) -> MessageMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.MessageMedia.messageMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, vcard: _4!, userId: _5!) + } + else { + return nil + } + } + static func parse_messageMediaPoll(_ reader: BufferReader) -> MessageMedia? { + var _1: Api.Poll? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Poll + } + var _2: Api.PollResults? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PollResults + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageMedia.messageMediaPoll(poll: _1!, results: _2!) + } + else { + return nil + } + } + + } + enum PaymentSavedCredentials: TypeConstructorDescription { + case paymentSavedCredentialsCard(id: String, title: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentSavedCredentialsCard(let id, let title): + if boxed { + buffer.appendInt32(-842892769) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentSavedCredentialsCard(let id, let title): + return ("paymentSavedCredentialsCard", [("id", id), ("title", title)]) + } + } + + static func parse_paymentSavedCredentialsCard(_ reader: BufferReader) -> PaymentSavedCredentials? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PaymentSavedCredentials.paymentSavedCredentialsCard(id: _1!, title: _2!) + } + else { + return nil + } + } + + } + enum Null: TypeConstructorDescription { + case null + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .null: + if boxed { + buffer.appendInt32(1450380236) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .null: + return ("null", []) + } + } + + static func parse_null(_ reader: BufferReader) -> Null? { + return Api.Null.null + } + + } + enum DocumentAttribute: TypeConstructorDescription { + case documentAttributeImageSize(w: Int32, h: Int32) + case documentAttributeAnimated + case documentAttributeSticker(flags: Int32, alt: String, stickerset: Api.InputStickerSet, maskCoords: Api.MaskCoords?) + case documentAttributeVideo(flags: Int32, duration: Int32, w: Int32, h: Int32) + case documentAttributeAudio(flags: Int32, duration: Int32, title: String?, performer: String?, waveform: Buffer?) + case documentAttributeFilename(fileName: String) + case documentAttributeHasStickers + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .documentAttributeImageSize(let w, let h): + if boxed { + buffer.appendInt32(1815593308) + } + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .documentAttributeAnimated: + if boxed { + buffer.appendInt32(297109817) + } + + break + case .documentAttributeSticker(let flags, let alt, let stickerset, let maskCoords): + if boxed { + buffer.appendInt32(1662637586) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(alt, buffer: buffer, boxed: false) + stickerset.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {maskCoords!.serialize(buffer, true)} + break + case .documentAttributeVideo(let flags, let duration, let w, let h): + if boxed { + buffer.appendInt32(250621158) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .documentAttributeAudio(let flags, let duration, let title, let performer, let waveform): + if boxed { + buffer.appendInt32(-1739392570) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(performer!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(waveform!, buffer: buffer, boxed: false)} + break + case .documentAttributeFilename(let fileName): + if boxed { + buffer.appendInt32(358154344) + } + serializeString(fileName, buffer: buffer, boxed: false) + break + case .documentAttributeHasStickers: + if boxed { + buffer.appendInt32(-1744710921) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .documentAttributeImageSize(let w, let h): + return ("documentAttributeImageSize", [("w", w), ("h", h)]) + case .documentAttributeAnimated: + return ("documentAttributeAnimated", []) + case .documentAttributeSticker(let flags, let alt, let stickerset, let maskCoords): + return ("documentAttributeSticker", [("flags", flags), ("alt", alt), ("stickerset", stickerset), ("maskCoords", maskCoords)]) + case .documentAttributeVideo(let flags, let duration, let w, let h): + return ("documentAttributeVideo", [("flags", flags), ("duration", duration), ("w", w), ("h", h)]) + case .documentAttributeAudio(let flags, let duration, let title, let performer, let waveform): + return ("documentAttributeAudio", [("flags", flags), ("duration", duration), ("title", title), ("performer", performer), ("waveform", waveform)]) + case .documentAttributeFilename(let fileName): + return ("documentAttributeFilename", [("fileName", fileName)]) + case .documentAttributeHasStickers: + return ("documentAttributeHasStickers", []) + } + } + + static func parse_documentAttributeImageSize(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.DocumentAttribute.documentAttributeImageSize(w: _1!, h: _2!) + } + else { + return nil + } + } + static func parse_documentAttributeAnimated(_ reader: BufferReader) -> DocumentAttribute? { + return Api.DocumentAttribute.documentAttributeAnimated + } + static func parse_documentAttributeSticker(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Api.InputStickerSet? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.InputStickerSet + } + var _4: Api.MaskCoords? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.MaskCoords + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.DocumentAttribute.documentAttributeSticker(flags: _1!, alt: _2!, stickerset: _3!, maskCoords: _4) + } + else { + return nil + } + } + static func parse_documentAttributeVideo(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.DocumentAttribute.documentAttributeVideo(flags: _1!, duration: _2!, w: _3!, h: _4!) + } + else { + return nil + } + } + static func parse_documentAttributeAudio(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.DocumentAttribute.documentAttributeAudio(flags: _1!, duration: _2!, title: _3, performer: _4, waveform: _5) + } + else { + return nil + } + } + static func parse_documentAttributeFilename(_ reader: BufferReader) -> DocumentAttribute? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.DocumentAttribute.documentAttributeFilename(fileName: _1!) + } + else { + return nil + } + } + static func parse_documentAttributeHasStickers(_ reader: BufferReader) -> DocumentAttribute? { + return Api.DocumentAttribute.documentAttributeHasStickers + } + + } + enum ChatPhoto: TypeConstructorDescription { + case chatPhotoEmpty + case chatPhoto(photoSmall: Api.FileLocation, photoBig: Api.FileLocation, dcId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatPhotoEmpty: + if boxed { + buffer.appendInt32(935395612) + } + + break + case .chatPhoto(let photoSmall, let photoBig, let dcId): + if boxed { + buffer.appendInt32(1197267925) + } + photoSmall.serialize(buffer, true) + photoBig.serialize(buffer, true) + serializeInt32(dcId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatPhotoEmpty: + return ("chatPhotoEmpty", []) + case .chatPhoto(let photoSmall, let photoBig, let dcId): + return ("chatPhoto", [("photoSmall", photoSmall), ("photoBig", photoBig), ("dcId", dcId)]) + } + } + + static func parse_chatPhotoEmpty(_ reader: BufferReader) -> ChatPhoto? { + return Api.ChatPhoto.chatPhotoEmpty + } + static func parse_chatPhoto(_ reader: BufferReader) -> ChatPhoto? { + var _1: Api.FileLocation? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _2: Api.FileLocation? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChatPhoto.chatPhoto(photoSmall: _1!, photoBig: _2!, dcId: _3!) + } + else { + return nil + } + } + + } + enum PageCaption: TypeConstructorDescription { + case pageCaption(text: Api.RichText, credit: Api.RichText) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageCaption(let text, let credit): + if boxed { + buffer.appendInt32(1869903447) + } + text.serialize(buffer, true) + credit.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageCaption(let text, let credit): + return ("pageCaption", [("text", text), ("credit", credit)]) + } + } + + static func parse_pageCaption(_ reader: BufferReader) -> PageCaption? { + var _1: Api.RichText? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.RichText + } + var _2: Api.RichText? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageCaption.pageCaption(text: _1!, credit: _2!) + } + else { + return nil + } + } + + } + enum UrlAuthResult: TypeConstructorDescription { + case urlAuthResultRequest(flags: Int32, bot: Api.User, domain: String) + case urlAuthResultAccepted(url: String) + case urlAuthResultDefault + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .urlAuthResultRequest(let flags, let bot, let domain): + if boxed { + buffer.appendInt32(-1831650802) + } + serializeInt32(flags, buffer: buffer, boxed: false) + bot.serialize(buffer, true) + serializeString(domain, buffer: buffer, boxed: false) + break + case .urlAuthResultAccepted(let url): + if boxed { + buffer.appendInt32(-1886646706) + } + serializeString(url, buffer: buffer, boxed: false) + break + case .urlAuthResultDefault: + if boxed { + buffer.appendInt32(-1445536993) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .urlAuthResultRequest(let flags, let bot, let domain): + return ("urlAuthResultRequest", [("flags", flags), ("bot", bot), ("domain", domain)]) + case .urlAuthResultAccepted(let url): + return ("urlAuthResultAccepted", [("url", url)]) + case .urlAuthResultDefault: + return ("urlAuthResultDefault", []) + } + } + + static func parse_urlAuthResultRequest(_ reader: BufferReader) -> UrlAuthResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.User? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.User + } + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.UrlAuthResult.urlAuthResultRequest(flags: _1!, bot: _2!, domain: _3!) + } + else { + return nil + } + } + static func parse_urlAuthResultAccepted(_ reader: BufferReader) -> UrlAuthResult? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.UrlAuthResult.urlAuthResultAccepted(url: _1!) + } + else { + return nil + } + } + static func parse_urlAuthResultDefault(_ reader: BufferReader) -> UrlAuthResult? { + return Api.UrlAuthResult.urlAuthResultDefault + } + + } + enum InputStickerSet: TypeConstructorDescription { + case inputStickerSetEmpty + case inputStickerSetID(id: Int64, accessHash: Int64) + case inputStickerSetShortName(shortName: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputStickerSetEmpty: + if boxed { + buffer.appendInt32(-4838507) + } + + break + case .inputStickerSetID(let id, let accessHash): + if boxed { + buffer.appendInt32(-1645763991) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputStickerSetShortName(let shortName): + if boxed { + buffer.appendInt32(-2044933984) + } + serializeString(shortName, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputStickerSetEmpty: + return ("inputStickerSetEmpty", []) + case .inputStickerSetID(let id, let accessHash): + return ("inputStickerSetID", [("id", id), ("accessHash", accessHash)]) + case .inputStickerSetShortName(let shortName): + return ("inputStickerSetShortName", [("shortName", shortName)]) + } + } + + static func parse_inputStickerSetEmpty(_ reader: BufferReader) -> InputStickerSet? { + return Api.InputStickerSet.inputStickerSetEmpty + } + static func parse_inputStickerSetID(_ reader: BufferReader) -> InputStickerSet? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputStickerSet.inputStickerSetID(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputStickerSetShortName(_ reader: BufferReader) -> InputStickerSet? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.InputStickerSet.inputStickerSetShortName(shortName: _1!) + } + else { + return nil + } + } + + } + enum BotInfo: TypeConstructorDescription { + case botInfo(userId: Int32, description: String, commands: [Api.BotCommand]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botInfo(let userId, let description, let commands): + if boxed { + buffer.appendInt32(-1729618630) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(commands.count)) + for item in commands { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botInfo(let userId, let description, let commands): + return ("botInfo", [("userId", userId), ("description", description), ("commands", commands)]) + } + } + + static func parse_botInfo(_ reader: BufferReader) -> BotInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.BotCommand]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.BotInfo.botInfo(userId: _1!, description: _2!, commands: _3!) + } + else { + return nil + } + } + + } + enum FoundGif: TypeConstructorDescription { + case foundGif(url: String, thumbUrl: String, contentUrl: String, contentType: String, w: Int32, h: Int32) + case foundGifCached(url: String, photo: Api.Photo, document: Api.Document) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .foundGif(let url, let thumbUrl, let contentUrl, let contentType, let w, let h): + if boxed { + buffer.appendInt32(372165663) + } + serializeString(url, buffer: buffer, boxed: false) + serializeString(thumbUrl, buffer: buffer, boxed: false) + serializeString(contentUrl, buffer: buffer, boxed: false) + serializeString(contentType, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .foundGifCached(let url, let photo, let document): + if boxed { + buffer.appendInt32(-1670052855) + } + serializeString(url, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + document.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .foundGif(let url, let thumbUrl, let contentUrl, let contentType, let w, let h): + return ("foundGif", [("url", url), ("thumbUrl", thumbUrl), ("contentUrl", contentUrl), ("contentType", contentType), ("w", w), ("h", h)]) + case .foundGifCached(let url, let photo, let document): + return ("foundGifCached", [("url", url), ("photo", photo), ("document", document)]) + } + } + + static func parse_foundGif(_ reader: BufferReader) -> FoundGif? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.FoundGif.foundGif(url: _1!, thumbUrl: _2!, contentUrl: _3!, contentType: _4!, w: _5!, h: _6!) + } + else { + return nil + } + } + static func parse_foundGifCached(_ reader: BufferReader) -> FoundGif? { + var _1: String? + _1 = parseString(reader) + var _2: Api.Photo? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _3: Api.Document? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Document + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.FoundGif.foundGifCached(url: _1!, photo: _2!, document: _3!) + } + else { + return nil + } + } + + } + enum User: TypeConstructorDescription { + case userEmpty(id: Int32) + case user(flags: Int32, id: Int32, accessHash: Int64?, firstName: String?, lastName: String?, username: String?, phone: String?, photo: Api.UserProfilePhoto?, status: Api.UserStatus?, botInfoVersion: Int32?, restrictionReason: String?, botInlinePlaceholder: String?, langCode: String?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .userEmpty(let id): + if boxed { + buffer.appendInt32(537022650) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .user(let flags, let id, let accessHash, let firstName, let lastName, let username, let phone, let photo, let status, let botInfoVersion, let restrictionReason, let botInlinePlaceholder, let langCode): + if boxed { + buffer.appendInt32(773059779) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt64(accessHash!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(firstName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(lastName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(username!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeString(phone!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {photo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {status!.serialize(buffer, true)} + if Int(flags) & Int(1 << 14) != 0 {serializeInt32(botInfoVersion!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 18) != 0 {serializeString(restrictionReason!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 19) != 0 {serializeString(botInlinePlaceholder!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 22) != 0 {serializeString(langCode!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .userEmpty(let id): + return ("userEmpty", [("id", id)]) + case .user(let flags, let id, let accessHash, let firstName, let lastName, let username, let phone, let photo, let status, let botInfoVersion, let restrictionReason, let botInlinePlaceholder, let langCode): + return ("user", [("flags", flags), ("id", id), ("accessHash", accessHash), ("firstName", firstName), ("lastName", lastName), ("username", username), ("phone", phone), ("photo", photo), ("status", status), ("botInfoVersion", botInfoVersion), ("restrictionReason", restrictionReason), ("botInlinePlaceholder", botInlinePlaceholder), ("langCode", langCode)]) + } + } + + static func parse_userEmpty(_ reader: BufferReader) -> User? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.User.userEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_user(_ reader: BufferReader) -> User? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt64() } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) } + var _8: Api.UserProfilePhoto? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.UserProfilePhoto + } } + var _9: Api.UserStatus? + if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.UserStatus + } } + var _10: Int32? + if Int(_1!) & Int(1 << 14) != 0 {_10 = reader.readInt32() } + var _11: String? + if Int(_1!) & Int(1 << 18) != 0 {_11 = parseString(reader) } + var _12: String? + if Int(_1!) & Int(1 << 19) != 0 {_12 = parseString(reader) } + var _13: String? + if Int(_1!) & Int(1 << 22) != 0 {_13 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil + let _c10 = (Int(_1!) & Int(1 << 14) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 18) == 0) || _11 != nil + let _c12 = (Int(_1!) & Int(1 << 19) == 0) || _12 != nil + let _c13 = (Int(_1!) & Int(1 << 22) == 0) || _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.User.user(flags: _1!, id: _2!, accessHash: _3, firstName: _4, lastName: _5, username: _6, phone: _7, photo: _8, status: _9, botInfoVersion: _10, restrictionReason: _11, botInlinePlaceholder: _12, langCode: _13) + } + else { + return nil + } + } + + } + enum Message: TypeConstructorDescription { + case messageEmpty(id: Int32) + case messageService(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, replyToMsgId: Int32?, date: Int32, action: Api.MessageAction) + case message(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, editDate: Int32?, postAuthor: String?, groupedId: Int64?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageEmpty(let id): + if boxed { + buffer.appendInt32(-2082087340) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .messageService(let flags, let id, let fromId, let toId, let replyToMsgId, let date, let action): + if boxed { + buffer.appendInt32(-1642487306) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 8) != 0 {serializeInt32(fromId!, buffer: buffer, boxed: false)} + toId.serialize(buffer, true) + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + serializeInt32(date, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId): + if boxed { + buffer.appendInt32(1157215293) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 8) != 0 {serializeInt32(fromId!, buffer: buffer, boxed: false)} + toId.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {fwdFrom!.serialize(buffer, true)} + if Int(flags) & Int(1 << 11) != 0 {serializeInt32(viaBotId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {replyMarkup!.serialize(buffer, true)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 10) != 0 {serializeInt32(views!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 15) != 0 {serializeInt32(editDate!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 16) != 0 {serializeString(postAuthor!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 17) != 0 {serializeInt64(groupedId!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageEmpty(let id): + return ("messageEmpty", [("id", id)]) + case .messageService(let flags, let id, let fromId, let toId, let replyToMsgId, let date, let action): + return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("replyToMsgId", replyToMsgId), ("date", date), ("action", action)]) + case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId): + return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId)]) + } + } + + static func parse_messageEmpty(_ reader: BufferReader) -> Message? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Message.messageEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_messageService(_ reader: BufferReader) -> Message? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 8) != 0 {_3 = reader.readInt32() } + var _4: Api.Peer? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _5: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_5 = reader.readInt32() } + var _6: Int32? + _6 = reader.readInt32() + var _7: Api.MessageAction? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.MessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.Message.messageService(flags: _1!, id: _2!, fromId: _3, toId: _4!, replyToMsgId: _5, date: _6!, action: _7!) + } + else { + return nil + } + } + static func parse_message(_ reader: BufferReader) -> Message? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 8) != 0 {_3 = reader.readInt32() } + var _4: Api.Peer? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _5: Api.MessageFwdHeader? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader + } } + var _6: Int32? + if Int(_1!) & Int(1 << 11) != 0 {_6 = reader.readInt32() } + var _7: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_7 = reader.readInt32() } + var _8: Int32? + _8 = reader.readInt32() + var _9: String? + _9 = parseString(reader) + var _10: Api.MessageMedia? + if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.MessageMedia + } } + var _11: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + var _12: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _13: Int32? + if Int(_1!) & Int(1 << 10) != 0 {_13 = reader.readInt32() } + var _14: Int32? + if Int(_1!) & Int(1 << 15) != 0 {_14 = reader.readInt32() } + var _15: String? + if Int(_1!) & Int(1 << 16) != 0 {_15 = parseString(reader) } + var _16: Int64? + if Int(_1!) & Int(1 << 17) != 0 {_16 = reader.readInt64() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 11) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = (Int(_1!) & Int(1 << 9) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 6) == 0) || _11 != nil + let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil + let _c13 = (Int(_1!) & Int(1 << 10) == 0) || _13 != nil + let _c14 = (Int(_1!) & Int(1 << 15) == 0) || _14 != nil + let _c15 = (Int(_1!) & Int(1 << 16) == 0) || _15 != nil + let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 { + return Api.Message.message(flags: _1!, id: _2!, fromId: _3, toId: _4!, fwdFrom: _5, viaBotId: _6, replyToMsgId: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, editDate: _14, postAuthor: _15, groupedId: _16) + } + else { + return nil + } + } + + } + enum InputFileLocation: TypeConstructorDescription { + case inputEncryptedFileLocation(id: Int64, accessHash: Int64) + case inputSecureFileLocation(id: Int64, accessHash: Int64) + case inputFileLocation(volumeId: Int64, localId: Int32, secret: Int64, fileReference: Buffer) + case inputPhotoFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String) + case inputDocumentFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String) + case inputPeerPhotoFileLocation(flags: Int32, peer: Api.InputPeer, volumeId: Int64, localId: Int32) + case inputStickerSetThumb(stickerset: Api.InputStickerSet, volumeId: Int64, localId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputEncryptedFileLocation(let id, let accessHash): + if boxed { + buffer.appendInt32(-182231723) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputSecureFileLocation(let id, let accessHash): + if boxed { + buffer.appendInt32(-876089816) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputFileLocation(let volumeId, let localId, let secret, let fileReference): + if boxed { + buffer.appendInt32(-539317279) + } + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + serializeInt64(secret, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + break + case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize): + if boxed { + buffer.appendInt32(1075322878) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + serializeString(thumbSize, buffer: buffer, boxed: false) + break + case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize): + if boxed { + buffer.appendInt32(-1160743548) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + serializeString(thumbSize, buffer: buffer, boxed: false) + break + case .inputPeerPhotoFileLocation(let flags, let peer, let volumeId, let localId): + if boxed { + buffer.appendInt32(668375447) + } + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + break + case .inputStickerSetThumb(let stickerset, let volumeId, let localId): + if boxed { + buffer.appendInt32(230353641) + } + stickerset.serialize(buffer, true) + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputEncryptedFileLocation(let id, let accessHash): + return ("inputEncryptedFileLocation", [("id", id), ("accessHash", accessHash)]) + case .inputSecureFileLocation(let id, let accessHash): + return ("inputSecureFileLocation", [("id", id), ("accessHash", accessHash)]) + case .inputFileLocation(let volumeId, let localId, let secret, let fileReference): + return ("inputFileLocation", [("volumeId", volumeId), ("localId", localId), ("secret", secret), ("fileReference", fileReference)]) + case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize): + return ("inputPhotoFileLocation", [("id", id), ("accessHash", accessHash), ("fileReference", fileReference), ("thumbSize", thumbSize)]) + case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize): + return ("inputDocumentFileLocation", [("id", id), ("accessHash", accessHash), ("fileReference", fileReference), ("thumbSize", thumbSize)]) + case .inputPeerPhotoFileLocation(let flags, let peer, let volumeId, let localId): + return ("inputPeerPhotoFileLocation", [("flags", flags), ("peer", peer), ("volumeId", volumeId), ("localId", localId)]) + case .inputStickerSetThumb(let stickerset, let volumeId, let localId): + return ("inputStickerSetThumb", [("stickerset", stickerset), ("volumeId", volumeId), ("localId", localId)]) + } + } + + static func parse_inputEncryptedFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputFileLocation.inputEncryptedFileLocation(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputSecureFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputFileLocation.inputSecureFileLocation(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputFileLocation.inputFileLocation(volumeId: _1!, localId: _2!, secret: _3!, fileReference: _4!) + } + else { + return nil + } + } + static func parse_inputPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Buffer? + _3 = parseBytes(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputFileLocation.inputPhotoFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!) + } + else { + return nil + } + } + static func parse_inputDocumentFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Buffer? + _3 = parseBytes(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputFileLocation.inputDocumentFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!) + } + else { + return nil + } + } + static func parse_inputPeerPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputPeer? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + var _3: Int64? + _3 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputFileLocation.inputPeerPhotoFileLocation(flags: _1!, peer: _2!, volumeId: _3!, localId: _4!) + } + else { + return nil + } + } + static func parse_inputStickerSetThumb(_ reader: BufferReader) -> InputFileLocation? { + var _1: Api.InputStickerSet? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputStickerSet + } + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputFileLocation.inputStickerSetThumb(stickerset: _1!, volumeId: _2!, localId: _3!) + } + else { + return nil + } + } + + } + enum GeoPoint: TypeConstructorDescription { + case geoPointEmpty + case geoPoint(long: Double, lat: Double, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .geoPointEmpty: + if boxed { + buffer.appendInt32(286776671) + } + + break + case .geoPoint(let long, let lat, let accessHash): + if boxed { + buffer.appendInt32(43446532) + } + serializeDouble(long, buffer: buffer, boxed: false) + serializeDouble(lat, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .geoPointEmpty: + return ("geoPointEmpty", []) + case .geoPoint(let long, let lat, let accessHash): + return ("geoPoint", [("long", long), ("lat", lat), ("accessHash", accessHash)]) + } + } + + static func parse_geoPointEmpty(_ reader: BufferReader) -> GeoPoint? { + return Api.GeoPoint.geoPointEmpty + } + static func parse_geoPoint(_ reader: BufferReader) -> GeoPoint? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.GeoPoint.geoPoint(long: _1!, lat: _2!, accessHash: _3!) + } + else { + return nil + } + } + + } + enum InputPhoneCall: TypeConstructorDescription { + case inputPhoneCall(id: Int64, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPhoneCall(let id, let accessHash): + if boxed { + buffer.appendInt32(506920429) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPhoneCall(let id, let accessHash): + return ("inputPhoneCall", [("id", id), ("accessHash", accessHash)]) + } + } + + static func parse_inputPhoneCall(_ reader: BufferReader) -> InputPhoneCall? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPhoneCall.inputPhoneCall(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum ReceivedNotifyMessage: TypeConstructorDescription { + case receivedNotifyMessage(id: Int32, flags: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .receivedNotifyMessage(let id, let flags): + if boxed { + buffer.appendInt32(-1551583367) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .receivedNotifyMessage(let id, let flags): + return ("receivedNotifyMessage", [("id", id), ("flags", flags)]) + } + } + + static func parse_receivedNotifyMessage(_ reader: BufferReader) -> ReceivedNotifyMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ReceivedNotifyMessage.receivedNotifyMessage(id: _1!, flags: _2!) + } + else { + return nil + } + } + + } + enum ChatParticipants: TypeConstructorDescription { + case chatParticipantsForbidden(flags: Int32, chatId: Int32, selfParticipant: Api.ChatParticipant?) + case chatParticipants(chatId: Int32, participants: [Api.ChatParticipant], version: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatParticipantsForbidden(let flags, let chatId, let selfParticipant): + if boxed { + buffer.appendInt32(-57668565) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {selfParticipant!.serialize(buffer, true)} + break + case .chatParticipants(let chatId, let participants, let version): + if boxed { + buffer.appendInt32(1061556205) + } + serializeInt32(chatId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(participants.count)) + for item in participants { + item.serialize(buffer, true) + } + serializeInt32(version, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatParticipantsForbidden(let flags, let chatId, let selfParticipant): + return ("chatParticipantsForbidden", [("flags", flags), ("chatId", chatId), ("selfParticipant", selfParticipant)]) + case .chatParticipants(let chatId, let participants, let version): + return ("chatParticipants", [("chatId", chatId), ("participants", participants), ("version", version)]) + } + } + + static func parse_chatParticipantsForbidden(_ reader: BufferReader) -> ChatParticipants? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.ChatParticipant? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.ChatParticipant + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChatParticipants.chatParticipantsForbidden(flags: _1!, chatId: _2!, selfParticipant: _3) + } + else { + return nil + } + } + static func parse_chatParticipants(_ reader: BufferReader) -> ChatParticipants? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.ChatParticipant]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatParticipant.self) + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ChatParticipants.chatParticipants(chatId: _1!, participants: _2!, version: _3!) + } + else { + return nil + } + } + + } + enum InputPaymentCredentials: TypeConstructorDescription { + case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer) + case inputPaymentCredentials(flags: Int32, data: Api.DataJSON) + case inputPaymentCredentialsApplePay(paymentData: Api.DataJSON) + case inputPaymentCredentialsAndroidPay(paymentToken: Api.DataJSON, googleTransactionId: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPaymentCredentialsSaved(let id, let tmpPassword): + if boxed { + buffer.appendInt32(-1056001329) + } + serializeString(id, buffer: buffer, boxed: false) + serializeBytes(tmpPassword, buffer: buffer, boxed: false) + break + case .inputPaymentCredentials(let flags, let data): + if boxed { + buffer.appendInt32(873977640) + } + serializeInt32(flags, buffer: buffer, boxed: false) + data.serialize(buffer, true) + break + case .inputPaymentCredentialsApplePay(let paymentData): + if boxed { + buffer.appendInt32(178373535) + } + paymentData.serialize(buffer, true) + break + case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId): + if boxed { + buffer.appendInt32(-905587442) + } + paymentToken.serialize(buffer, true) + serializeString(googleTransactionId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPaymentCredentialsSaved(let id, let tmpPassword): + return ("inputPaymentCredentialsSaved", [("id", id), ("tmpPassword", tmpPassword)]) + case .inputPaymentCredentials(let flags, let data): + return ("inputPaymentCredentials", [("flags", flags), ("data", data)]) + case .inputPaymentCredentialsApplePay(let paymentData): + return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData)]) + case .inputPaymentCredentialsAndroidPay(let paymentToken, let googleTransactionId): + return ("inputPaymentCredentialsAndroidPay", [("paymentToken", paymentToken), ("googleTransactionId", googleTransactionId)]) + } + } + + static func parse_inputPaymentCredentialsSaved(_ reader: BufferReader) -> InputPaymentCredentials? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPaymentCredentials.inputPaymentCredentialsSaved(id: _1!, tmpPassword: _2!) + } + else { + return nil + } + } + static func parse_inputPaymentCredentials(_ reader: BufferReader) -> InputPaymentCredentials? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.DataJSON? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPaymentCredentials.inputPaymentCredentials(flags: _1!, data: _2!) + } + else { + return nil + } + } + static func parse_inputPaymentCredentialsApplePay(_ reader: BufferReader) -> InputPaymentCredentials? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + if _c1 { + return Api.InputPaymentCredentials.inputPaymentCredentialsApplePay(paymentData: _1!) + } + else { + return nil + } + } + static func parse_inputPaymentCredentialsAndroidPay(_ reader: BufferReader) -> InputPaymentCredentials? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputPaymentCredentials.inputPaymentCredentialsAndroidPay(paymentToken: _1!, googleTransactionId: _2!) + } + else { + return nil + } + } + + } + enum ShippingOption: TypeConstructorDescription { + case shippingOption(id: String, title: String, prices: [Api.LabeledPrice]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .shippingOption(let id, let title, let prices): + if boxed { + buffer.appendInt32(-1239335713) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(prices.count)) + for item in prices { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .shippingOption(let id, let title, let prices): + return ("shippingOption", [("id", id), ("title", title), ("prices", prices)]) + } + } + + static func parse_shippingOption(_ reader: BufferReader) -> ShippingOption? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: [Api.LabeledPrice]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LabeledPrice.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.ShippingOption.shippingOption(id: _1!, title: _2!, prices: _3!) + } + else { + return nil + } + } + + } + enum InputSecureFile: TypeConstructorDescription { + case inputSecureFileUploaded(id: Int64, parts: Int32, md5Checksum: String, fileHash: Buffer, secret: Buffer) + case inputSecureFile(id: Int64, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputSecureFileUploaded(let id, let parts, let md5Checksum, let fileHash, let secret): + if boxed { + buffer.appendInt32(859091184) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(parts, buffer: buffer, boxed: false) + serializeString(md5Checksum, buffer: buffer, boxed: false) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeBytes(secret, buffer: buffer, boxed: false) + break + case .inputSecureFile(let id, let accessHash): + if boxed { + buffer.appendInt32(1399317950) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputSecureFileUploaded(let id, let parts, let md5Checksum, let fileHash, let secret): + return ("inputSecureFileUploaded", [("id", id), ("parts", parts), ("md5Checksum", md5Checksum), ("fileHash", fileHash), ("secret", secret)]) + case .inputSecureFile(let id, let accessHash): + return ("inputSecureFile", [("id", id), ("accessHash", accessHash)]) + } + } + + static func parse_inputSecureFileUploaded(_ reader: BufferReader) -> InputSecureFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.InputSecureFile.inputSecureFileUploaded(id: _1!, parts: _2!, md5Checksum: _3!, fileHash: _4!, secret: _5!) + } + else { + return nil + } + } + static func parse_inputSecureFile(_ reader: BufferReader) -> InputSecureFile? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputSecureFile.inputSecureFile(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + + } + enum PostAddress: TypeConstructorDescription { + case postAddress(streetLine1: String, streetLine2: String, city: String, state: String, countryIso2: String, postCode: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .postAddress(let streetLine1, let streetLine2, let city, let state, let countryIso2, let postCode): + if boxed { + buffer.appendInt32(512535275) + } + serializeString(streetLine1, buffer: buffer, boxed: false) + serializeString(streetLine2, buffer: buffer, boxed: false) + serializeString(city, buffer: buffer, boxed: false) + serializeString(state, buffer: buffer, boxed: false) + serializeString(countryIso2, buffer: buffer, boxed: false) + serializeString(postCode, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .postAddress(let streetLine1, let streetLine2, let city, let state, let countryIso2, let postCode): + return ("postAddress", [("streetLine1", streetLine1), ("streetLine2", streetLine2), ("city", city), ("state", state), ("countryIso2", countryIso2), ("postCode", postCode)]) + } + } + + static func parse_postAddress(_ reader: BufferReader) -> PostAddress? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.PostAddress.postAddress(streetLine1: _1!, streetLine2: _2!, city: _3!, state: _4!, countryIso2: _5!, postCode: _6!) + } + else { + return nil + } + } + + } + enum InputFolderPeer: TypeConstructorDescription { + case inputFolderPeer(peer: Api.InputPeer, folderId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputFolderPeer(let peer, let folderId): + if boxed { + buffer.appendInt32(-70073706) + } + peer.serialize(buffer, true) + serializeInt32(folderId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputFolderPeer(let peer, let folderId): + return ("inputFolderPeer", [("peer", peer), ("folderId", folderId)]) + } + } + + static func parse_inputFolderPeer(_ reader: BufferReader) -> InputFolderPeer? { + var _1: Api.InputPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputFolderPeer.inputFolderPeer(peer: _1!, folderId: _2!) + } + else { + return nil + } + } + + } + enum DataJSON: TypeConstructorDescription { + case dataJSON(data: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dataJSON(let data): + if boxed { + buffer.appendInt32(2104790276) + } + serializeString(data, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dataJSON(let data): + return ("dataJSON", [("data", data)]) + } + } + + static func parse_dataJSON(_ reader: BufferReader) -> DataJSON? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.DataJSON.dataJSON(data: _1!) + } + else { + return nil + } + } + + } + enum InputWallPaper: TypeConstructorDescription { + case inputWallPaper(id: Int64, accessHash: Int64) + case inputWallPaperSlug(slug: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputWallPaper(let id, let accessHash): + if boxed { + buffer.appendInt32(-433014407) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputWallPaperSlug(let slug): + if boxed { + buffer.appendInt32(1913199744) + } + serializeString(slug, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputWallPaper(let id, let accessHash): + return ("inputWallPaper", [("id", id), ("accessHash", accessHash)]) + case .inputWallPaperSlug(let slug): + return ("inputWallPaperSlug", [("slug", slug)]) + } + } + + static func parse_inputWallPaper(_ reader: BufferReader) -> InputWallPaper? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputWallPaper.inputWallPaper(id: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputWallPaperSlug(_ reader: BufferReader) -> InputWallPaper? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.InputWallPaper.inputWallPaperSlug(slug: _1!) + } + else { + return nil + } + } + + } + enum InputStickeredMedia: TypeConstructorDescription { + case inputStickeredMediaPhoto(id: Api.InputPhoto) + case inputStickeredMediaDocument(id: Api.InputDocument) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputStickeredMediaPhoto(let id): + if boxed { + buffer.appendInt32(1251549527) + } + id.serialize(buffer, true) + break + case .inputStickeredMediaDocument(let id): + if boxed { + buffer.appendInt32(70813275) + } + id.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputStickeredMediaPhoto(let id): + return ("inputStickeredMediaPhoto", [("id", id)]) + case .inputStickeredMediaDocument(let id): + return ("inputStickeredMediaDocument", [("id", id)]) + } + } + + static func parse_inputStickeredMediaPhoto(_ reader: BufferReader) -> InputStickeredMedia? { + var _1: Api.InputPhoto? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPhoto + } + let _c1 = _1 != nil + if _c1 { + return Api.InputStickeredMedia.inputStickeredMediaPhoto(id: _1!) + } + else { + return nil + } + } + static func parse_inputStickeredMediaDocument(_ reader: BufferReader) -> InputStickeredMedia? { + var _1: Api.InputDocument? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputDocument + } + let _c1 = _1 != nil + if _c1 { + return Api.InputStickeredMedia.inputStickeredMediaDocument(id: _1!) + } + else { + return nil + } + } + + } + enum PhoneCallDiscardReason: TypeConstructorDescription { + case phoneCallDiscardReasonMissed + case phoneCallDiscardReasonDisconnect + case phoneCallDiscardReasonHangup + case phoneCallDiscardReasonBusy + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .phoneCallDiscardReasonMissed: + if boxed { + buffer.appendInt32(-2048646399) + } + + break + case .phoneCallDiscardReasonDisconnect: + if boxed { + buffer.appendInt32(-527056480) + } + + break + case .phoneCallDiscardReasonHangup: + if boxed { + buffer.appendInt32(1471006352) + } + + break + case .phoneCallDiscardReasonBusy: + if boxed { + buffer.appendInt32(-84416311) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .phoneCallDiscardReasonMissed: + return ("phoneCallDiscardReasonMissed", []) + case .phoneCallDiscardReasonDisconnect: + return ("phoneCallDiscardReasonDisconnect", []) + case .phoneCallDiscardReasonHangup: + return ("phoneCallDiscardReasonHangup", []) + case .phoneCallDiscardReasonBusy: + return ("phoneCallDiscardReasonBusy", []) + } + } + + static func parse_phoneCallDiscardReasonMissed(_ reader: BufferReader) -> PhoneCallDiscardReason? { + return Api.PhoneCallDiscardReason.phoneCallDiscardReasonMissed + } + static func parse_phoneCallDiscardReasonDisconnect(_ reader: BufferReader) -> PhoneCallDiscardReason? { + return Api.PhoneCallDiscardReason.phoneCallDiscardReasonDisconnect + } + static func parse_phoneCallDiscardReasonHangup(_ reader: BufferReader) -> PhoneCallDiscardReason? { + return Api.PhoneCallDiscardReason.phoneCallDiscardReasonHangup + } + static func parse_phoneCallDiscardReasonBusy(_ reader: BufferReader) -> PhoneCallDiscardReason? { + return Api.PhoneCallDiscardReason.phoneCallDiscardReasonBusy + } + + } + enum NearestDc: TypeConstructorDescription { + case nearestDc(country: String, thisDc: Int32, nearestDc: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .nearestDc(let country, let thisDc, let nearestDc): + if boxed { + buffer.appendInt32(-1910892683) + } + serializeString(country, buffer: buffer, boxed: false) + serializeInt32(thisDc, buffer: buffer, boxed: false) + serializeInt32(nearestDc, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .nearestDc(let country, let thisDc, let nearestDc): + return ("nearestDc", [("country", country), ("thisDc", thisDc), ("nearestDc", nearestDc)]) + } + } + + static func parse_nearestDc(_ reader: BufferReader) -> NearestDc? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.NearestDc.nearestDc(country: _1!, thisDc: _2!, nearestDc: _3!) + } + else { + return nil + } + } + + } + enum JSONObjectValue: TypeConstructorDescription { + case jsonObjectValue(key: String, value: Api.JSONValue) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .jsonObjectValue(let key, let value): + if boxed { + buffer.appendInt32(-1059185703) + } + serializeString(key, buffer: buffer, boxed: false) + value.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .jsonObjectValue(let key, let value): + return ("jsonObjectValue", [("key", key), ("value", value)]) + } + } + + static func parse_jsonObjectValue(_ reader: BufferReader) -> JSONObjectValue? { + var _1: String? + _1 = parseString(reader) + var _2: Api.JSONValue? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.JSONValue + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.JSONObjectValue.jsonObjectValue(key: _1!, value: _2!) + } + else { + return nil + } + } + + } + enum InputWebDocument: TypeConstructorDescription { + case inputWebDocument(url: String, size: Int32, mimeType: String, attributes: [Api.DocumentAttribute]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputWebDocument(let url, let size, let mimeType, let attributes): + if boxed { + buffer.appendInt32(-1678949555) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputWebDocument(let url, let size, let mimeType, let attributes): + return ("inputWebDocument", [("url", url), ("size", size), ("mimeType", mimeType), ("attributes", attributes)]) + } + } + + static func parse_inputWebDocument(_ reader: BufferReader) -> InputWebDocument? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputWebDocument.inputWebDocument(url: _1!, size: _2!, mimeType: _3!, attributes: _4!) + } + else { + return nil + } + } + + } + enum ChannelAdminLogEvent: TypeConstructorDescription { + case channelAdminLogEvent(id: Int64, date: Int32, userId: Int32, action: Api.ChannelAdminLogEventAction) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelAdminLogEvent(let id, let date, let userId, let action): + if boxed { + buffer.appendInt32(995769920) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelAdminLogEvent(let id, let date, let userId, let action): + return ("channelAdminLogEvent", [("id", id), ("date", date), ("userId", userId), ("action", action)]) + } + } + + static func parse_channelAdminLogEvent(_ reader: BufferReader) -> ChannelAdminLogEvent? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Api.ChannelAdminLogEventAction? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ChannelAdminLogEventAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.ChannelAdminLogEvent.channelAdminLogEvent(id: _1!, date: _2!, userId: _3!, action: _4!) + } + else { + return nil + } + } + + } + enum Bool: TypeConstructorDescription { + case boolFalse + case boolTrue + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .boolFalse: + if boxed { + buffer.appendInt32(-1132882121) + } + + break + case .boolTrue: + if boxed { + buffer.appendInt32(-1720552011) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .boolFalse: + return ("boolFalse", []) + case .boolTrue: + return ("boolTrue", []) + } + } + + static func parse_boolFalse(_ reader: BufferReader) -> Bool? { + return Api.Bool.boolFalse + } + static func parse_boolTrue(_ reader: BufferReader) -> Bool? { + return Api.Bool.boolTrue + } + + } + enum LangPackString: TypeConstructorDescription { + case langPackString(key: String, value: String) + case langPackStringPluralized(flags: Int32, key: String, zeroValue: String?, oneValue: String?, twoValue: String?, fewValue: String?, manyValue: String?, otherValue: String) + case langPackStringDeleted(key: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .langPackString(let key, let value): + if boxed { + buffer.appendInt32(-892239370) + } + serializeString(key, buffer: buffer, boxed: false) + serializeString(value, buffer: buffer, boxed: false) + break + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + if boxed { + buffer.appendInt32(1816636575) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(key, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(zeroValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(oneValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(twoValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(fewValue!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeString(manyValue!, buffer: buffer, boxed: false)} + serializeString(otherValue, buffer: buffer, boxed: false) + break + case .langPackStringDeleted(let key): + if boxed { + buffer.appendInt32(695856818) + } + serializeString(key, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .langPackString(let key, let value): + return ("langPackString", [("key", key), ("value", value)]) + case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue): + return ("langPackStringPluralized", [("flags", flags), ("key", key), ("zeroValue", zeroValue), ("oneValue", oneValue), ("twoValue", twoValue), ("fewValue", fewValue), ("manyValue", manyValue), ("otherValue", otherValue)]) + case .langPackStringDeleted(let key): + return ("langPackStringDeleted", [("key", key)]) + } + } + + static func parse_langPackString(_ reader: BufferReader) -> LangPackString? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.LangPackString.langPackString(key: _1!, value: _2!) + } + else { + return nil + } + } + static func parse_langPackStringPluralized(_ reader: BufferReader) -> LangPackString? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: String? + if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) } + var _8: String? + _8 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.LangPackString.langPackStringPluralized(flags: _1!, key: _2!, zeroValue: _3, oneValue: _4, twoValue: _5, fewValue: _6, manyValue: _7, otherValue: _8!) + } + else { + return nil + } + } + static func parse_langPackStringDeleted(_ reader: BufferReader) -> LangPackString? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.LangPackString.langPackStringDeleted(key: _1!) + } + else { + return nil + } + } + + } + enum InputWebFileLocation: TypeConstructorDescription { + case inputWebFileLocation(url: String, accessHash: Int64) + case inputWebFileGeoMessageLocation(peer: Api.InputPeer, msgId: Int32, w: Int32, h: Int32, zoom: Int32, scale: Int32) + case inputWebFileGeoPointLocation(geoPoint: Api.InputGeoPoint, accessHash: Int64, w: Int32, h: Int32, zoom: Int32, scale: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputWebFileLocation(let url, let accessHash): + if boxed { + buffer.appendInt32(-1036396922) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputWebFileGeoMessageLocation(let peer, let msgId, let w, let h, let zoom, let scale): + if boxed { + buffer.appendInt32(1430205163) + } + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(zoom, buffer: buffer, boxed: false) + serializeInt32(scale, buffer: buffer, boxed: false) + break + case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): + if boxed { + buffer.appendInt32(-1625153079) + } + geoPoint.serialize(buffer, true) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(zoom, buffer: buffer, boxed: false) + serializeInt32(scale, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputWebFileLocation(let url, let accessHash): + return ("inputWebFileLocation", [("url", url), ("accessHash", accessHash)]) + case .inputWebFileGeoMessageLocation(let peer, let msgId, let w, let h, let zoom, let scale): + return ("inputWebFileGeoMessageLocation", [("peer", peer), ("msgId", msgId), ("w", w), ("h", h), ("zoom", zoom), ("scale", scale)]) + case .inputWebFileGeoPointLocation(let geoPoint, let accessHash, let w, let h, let zoom, let scale): + return ("inputWebFileGeoPointLocation", [("geoPoint", geoPoint), ("accessHash", accessHash), ("w", w), ("h", h), ("zoom", zoom), ("scale", scale)]) + } + } + + static func parse_inputWebFileLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputWebFileLocation.inputWebFileLocation(url: _1!, accessHash: _2!) + } + else { + return nil + } + } + static func parse_inputWebFileGeoMessageLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: Api.InputPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputWebFileLocation.inputWebFileGeoMessageLocation(peer: _1!, msgId: _2!, w: _3!, h: _4!, zoom: _5!, scale: _6!) + } + else { + return nil + } + } + static func parse_inputWebFileGeoPointLocation(_ reader: BufferReader) -> InputWebFileLocation? { + var _1: Api.InputGeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint + } + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputWebFileLocation.inputWebFileGeoPointLocation(geoPoint: _1!, accessHash: _2!, w: _3!, h: _4!, zoom: _5!, scale: _6!) + } + else { + return nil + } + } + + } + enum MessageFwdHeader: TypeConstructorDescription { + case messageFwdHeader(flags: Int32, fromId: Int32?, fromName: String?, date: Int32, channelId: Int32?, channelPost: Int32?, postAuthor: String?, savedFromPeer: Api.Peer?, savedFromMsgId: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageFwdHeader(let flags, let fromId, let fromName, let date, let channelId, let channelPost, let postAuthor, let savedFromPeer, let savedFromMsgId): + if boxed { + buffer.appendInt32(-332168592) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(fromId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 5) != 0 {serializeString(fromName!, buffer: buffer, boxed: false)} + serializeInt32(date, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(channelId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(channelPost!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(postAuthor!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {savedFromPeer!.serialize(buffer, true)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(savedFromMsgId!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageFwdHeader(let flags, let fromId, let fromName, let date, let channelId, let channelPost, let postAuthor, let savedFromPeer, let savedFromMsgId): + return ("messageFwdHeader", [("flags", flags), ("fromId", fromId), ("fromName", fromName), ("date", date), ("channelId", channelId), ("channelPost", channelPost), ("postAuthor", postAuthor), ("savedFromPeer", savedFromPeer), ("savedFromMsgId", savedFromMsgId)]) + } + } + + static func parse_messageFwdHeader(_ reader: BufferReader) -> MessageFwdHeader? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: String? + if Int(_1!) & Int(1 << 5) != 0 {_3 = parseString(reader) } + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } + var _6: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt32() } + var _7: String? + if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) } + var _8: Api.Peer? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.Peer + } } + var _9: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_9 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 5) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 4) == 0) || _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.MessageFwdHeader.messageFwdHeader(flags: _1!, fromId: _2, fromName: _3, date: _4!, channelId: _5, channelPost: _6, postAuthor: _7, savedFromPeer: _8, savedFromMsgId: _9) + } + else { + return nil + } + } + + } + enum MessagesFilter: TypeConstructorDescription { + case inputMessagesFilterEmpty + case inputMessagesFilterPhotos + case inputMessagesFilterVideo + case inputMessagesFilterPhotoVideo + case inputMessagesFilterPhotoVideoDocuments + case inputMessagesFilterDocument + case inputMessagesFilterUrl + case inputMessagesFilterGif + case inputMessagesFilterVoice + case inputMessagesFilterMusic + case inputMessagesFilterChatPhotos + case inputMessagesFilterPhoneCalls(flags: Int32) + case inputMessagesFilterRoundVoice + case inputMessagesFilterRoundVideo + case inputMessagesFilterMyMentions + case inputMessagesFilterMyMentionsUnread + case inputMessagesFilterGeo + case inputMessagesFilterContacts + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputMessagesFilterEmpty: + if boxed { + buffer.appendInt32(1474492012) + } + + break + case .inputMessagesFilterPhotos: + if boxed { + buffer.appendInt32(-1777752804) + } + + break + case .inputMessagesFilterVideo: + if boxed { + buffer.appendInt32(-1614803355) + } + + break + case .inputMessagesFilterPhotoVideo: + if boxed { + buffer.appendInt32(1458172132) + } + + break + case .inputMessagesFilterPhotoVideoDocuments: + if boxed { + buffer.appendInt32(-648121413) + } + + break + case .inputMessagesFilterDocument: + if boxed { + buffer.appendInt32(-1629621880) + } + + break + case .inputMessagesFilterUrl: + if boxed { + buffer.appendInt32(2129714567) + } + + break + case .inputMessagesFilterGif: + if boxed { + buffer.appendInt32(-3644025) + } + + break + case .inputMessagesFilterVoice: + if boxed { + buffer.appendInt32(1358283666) + } + + break + case .inputMessagesFilterMusic: + if boxed { + buffer.appendInt32(928101534) + } + + break + case .inputMessagesFilterChatPhotos: + if boxed { + buffer.appendInt32(975236280) + } + + break + case .inputMessagesFilterPhoneCalls(let flags): + if boxed { + buffer.appendInt32(-2134272152) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + case .inputMessagesFilterRoundVoice: + if boxed { + buffer.appendInt32(2054952868) + } + + break + case .inputMessagesFilterRoundVideo: + if boxed { + buffer.appendInt32(-1253451181) + } + + break + case .inputMessagesFilterMyMentions: + if boxed { + buffer.appendInt32(-1040652646) + } + + break + case .inputMessagesFilterMyMentionsUnread: + if boxed { + buffer.appendInt32(1187706024) + } + + break + case .inputMessagesFilterGeo: + if boxed { + buffer.appendInt32(-419271411) + } + + break + case .inputMessagesFilterContacts: + if boxed { + buffer.appendInt32(-530392189) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputMessagesFilterEmpty: + return ("inputMessagesFilterEmpty", []) + case .inputMessagesFilterPhotos: + return ("inputMessagesFilterPhotos", []) + case .inputMessagesFilterVideo: + return ("inputMessagesFilterVideo", []) + case .inputMessagesFilterPhotoVideo: + return ("inputMessagesFilterPhotoVideo", []) + case .inputMessagesFilterPhotoVideoDocuments: + return ("inputMessagesFilterPhotoVideoDocuments", []) + case .inputMessagesFilterDocument: + return ("inputMessagesFilterDocument", []) + case .inputMessagesFilterUrl: + return ("inputMessagesFilterUrl", []) + case .inputMessagesFilterGif: + return ("inputMessagesFilterGif", []) + case .inputMessagesFilterVoice: + return ("inputMessagesFilterVoice", []) + case .inputMessagesFilterMusic: + return ("inputMessagesFilterMusic", []) + case .inputMessagesFilterChatPhotos: + return ("inputMessagesFilterChatPhotos", []) + case .inputMessagesFilterPhoneCalls(let flags): + return ("inputMessagesFilterPhoneCalls", [("flags", flags)]) + case .inputMessagesFilterRoundVoice: + return ("inputMessagesFilterRoundVoice", []) + case .inputMessagesFilterRoundVideo: + return ("inputMessagesFilterRoundVideo", []) + case .inputMessagesFilterMyMentions: + return ("inputMessagesFilterMyMentions", []) + case .inputMessagesFilterMyMentionsUnread: + return ("inputMessagesFilterMyMentionsUnread", []) + case .inputMessagesFilterGeo: + return ("inputMessagesFilterGeo", []) + case .inputMessagesFilterContacts: + return ("inputMessagesFilterContacts", []) + } + } + + static func parse_inputMessagesFilterEmpty(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterEmpty + } + static func parse_inputMessagesFilterPhotos(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterPhotos + } + static func parse_inputMessagesFilterVideo(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterVideo + } + static func parse_inputMessagesFilterPhotoVideo(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterPhotoVideo + } + static func parse_inputMessagesFilterPhotoVideoDocuments(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterPhotoVideoDocuments + } + static func parse_inputMessagesFilterDocument(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterDocument + } + static func parse_inputMessagesFilterUrl(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterUrl + } + static func parse_inputMessagesFilterGif(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterGif + } + static func parse_inputMessagesFilterVoice(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterVoice + } + static func parse_inputMessagesFilterMusic(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterMusic + } + static func parse_inputMessagesFilterChatPhotos(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterChatPhotos + } + static func parse_inputMessagesFilterPhoneCalls(_ reader: BufferReader) -> MessagesFilter? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessagesFilter.inputMessagesFilterPhoneCalls(flags: _1!) + } + else { + return nil + } + } + static func parse_inputMessagesFilterRoundVoice(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterRoundVoice + } + static func parse_inputMessagesFilterRoundVideo(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterRoundVideo + } + static func parse_inputMessagesFilterMyMentions(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterMyMentions + } + static func parse_inputMessagesFilterMyMentionsUnread(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterMyMentionsUnread + } + static func parse_inputMessagesFilterGeo(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterGeo + } + static func parse_inputMessagesFilterContacts(_ reader: BufferReader) -> MessagesFilter? { + return Api.MessagesFilter.inputMessagesFilterContacts + } + + } + enum EmojiKeyword: TypeConstructorDescription { + case emojiKeyword(keyword: String, emoticons: [String]) + case emojiKeywordDeleted(keyword: String, emoticons: [String]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .emojiKeyword(let keyword, let emoticons): + if boxed { + buffer.appendInt32(-709641735) + } + serializeString(keyword, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(emoticons.count)) + for item in emoticons { + serializeString(item, buffer: buffer, boxed: false) + } + break + case .emojiKeywordDeleted(let keyword, let emoticons): + if boxed { + buffer.appendInt32(594408994) + } + serializeString(keyword, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(emoticons.count)) + for item in emoticons { + serializeString(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .emojiKeyword(let keyword, let emoticons): + return ("emojiKeyword", [("keyword", keyword), ("emoticons", emoticons)]) + case .emojiKeywordDeleted(let keyword, let emoticons): + return ("emojiKeywordDeleted", [("keyword", keyword), ("emoticons", emoticons)]) + } + } + + static func parse_emojiKeyword(_ reader: BufferReader) -> EmojiKeyword? { + var _1: String? + _1 = parseString(reader) + var _2: [String]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.EmojiKeyword.emojiKeyword(keyword: _1!, emoticons: _2!) + } + else { + return nil + } + } + static func parse_emojiKeywordDeleted(_ reader: BufferReader) -> EmojiKeyword? { + var _1: String? + _1 = parseString(reader) + var _2: [String]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.EmojiKeyword.emojiKeywordDeleted(keyword: _1!, emoticons: _2!) + } + else { + return nil + } + } + + } + enum BotInlineMessage: TypeConstructorDescription { + case botInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?) + case botInlineMessageMediaGeo(flags: Int32, geo: Api.GeoPoint, replyMarkup: Api.ReplyMarkup?) + case botInlineMessageMediaAuto(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?) + case botInlineMessageMediaVenue(flags: Int32, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?) + case botInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .botInlineMessageText(let flags, let message, let entities, let replyMarkup): + if boxed { + buffer.appendInt32(-1937807902) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .botInlineMessageMediaGeo(let flags, let geo, let replyMarkup): + if boxed { + buffer.appendInt32(982505656) + } + serializeInt32(flags, buffer: buffer, boxed: false) + geo.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .botInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup): + if boxed { + buffer.appendInt32(1984755728) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .botInlineMessageMediaVenue(let flags, let geo, let title, let address, let provider, let venueId, let venueType, let replyMarkup): + if boxed { + buffer.appendInt32(-1970903652) + } + serializeInt32(flags, buffer: buffer, boxed: false) + geo.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + serializeString(venueType, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + case .botInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup): + if boxed { + buffer.appendInt32(416402882) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(vcard, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .botInlineMessageText(let flags, let message, let entities, let replyMarkup): + return ("botInlineMessageText", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)]) + case .botInlineMessageMediaGeo(let flags, let geo, let replyMarkup): + return ("botInlineMessageMediaGeo", [("flags", flags), ("geo", geo), ("replyMarkup", replyMarkup)]) + case .botInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup): + return ("botInlineMessageMediaAuto", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)]) + case .botInlineMessageMediaVenue(let flags, let geo, let title, let address, let provider, let venueId, let venueType, let replyMarkup): + return ("botInlineMessageMediaVenue", [("flags", flags), ("geo", geo), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType), ("replyMarkup", replyMarkup)]) + case .botInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup): + return ("botInlineMessageMediaContact", [("flags", flags), ("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("replyMarkup", replyMarkup)]) + } + } + + static func parse_botInlineMessageText(_ reader: BufferReader) -> BotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _4: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.BotInlineMessage.botInlineMessageText(flags: _1!, message: _2!, entities: _3, replyMarkup: _4) + } + else { + return nil + } + } + static func parse_botInlineMessageMediaGeo(_ reader: BufferReader) -> BotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.GeoPoint? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _3: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.BotInlineMessage.botInlineMessageMediaGeo(flags: _1!, geo: _2!, replyMarkup: _3) + } + else { + return nil + } + } + static func parse_botInlineMessageMediaAuto(_ reader: BufferReader) -> BotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + var _4: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.BotInlineMessage.botInlineMessageMediaAuto(flags: _1!, message: _2!, entities: _3, replyMarkup: _4) + } + else { + return nil + } + } + static func parse_botInlineMessageMediaVenue(_ reader: BufferReader) -> BotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.GeoPoint? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + var _7: String? + _7 = parseString(reader) + var _8: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.BotInlineMessage.botInlineMessageMediaVenue(flags: _1!, geo: _2!, title: _3!, address: _4!, provider: _5!, venueId: _6!, venueType: _7!, replyMarkup: _8) + } + else { + return nil + } + } + static func parse_botInlineMessageMediaContact(_ reader: BufferReader) -> BotInlineMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Api.ReplyMarkup? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.BotInlineMessage.botInlineMessageMediaContact(flags: _1!, phoneNumber: _2!, firstName: _3!, lastName: _4!, vcard: _5!, replyMarkup: _6) + } + else { + return nil + } + } + + } + enum InputPeerNotifySettings: TypeConstructorDescription { + case inputPeerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: String?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPeerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): + if boxed { + buffer.appendInt32(-1673717362) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {showPreviews!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {silent!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(muteUntil!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(sound!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPeerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): + return ("inputPeerNotifySettings", [("flags", flags), ("showPreviews", showPreviews), ("silent", silent), ("muteUntil", muteUntil), ("sound", sound)]) + } + } + + static func parse_inputPeerNotifySettings(_ reader: BufferReader) -> InputPeerNotifySettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Bool? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Bool + } } + var _3: Api.Bool? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Bool + } } + var _4: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: _1!, showPreviews: _2, silent: _3, muteUntil: _4, sound: _5) + } + else { + return nil + } + } + + } + enum ExportedChatInvite: TypeConstructorDescription { + case chatInviteEmpty + case chatInviteExported(link: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatInviteEmpty: + if boxed { + buffer.appendInt32(1776236393) + } + + break + case .chatInviteExported(let link): + if boxed { + buffer.appendInt32(-64092740) + } + serializeString(link, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatInviteEmpty: + return ("chatInviteEmpty", []) + case .chatInviteExported(let link): + return ("chatInviteExported", [("link", link)]) + } + } + + static func parse_chatInviteEmpty(_ reader: BufferReader) -> ExportedChatInvite? { + return Api.ExportedChatInvite.chatInviteEmpty + } + static func parse_chatInviteExported(_ reader: BufferReader) -> ExportedChatInvite? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ExportedChatInvite.chatInviteExported(link: _1!) + } + else { + return nil + } + } + + } + enum Authorization: TypeConstructorDescription { + case authorization(flags: Int32, hash: Int64, deviceModel: String, platform: String, systemVersion: String, apiId: Int32, appName: String, appVersion: String, dateCreated: Int32, dateActive: Int32, ip: String, country: String, region: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .authorization(let flags, let hash, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let dateCreated, let dateActive, let ip, let country, let region): + if boxed { + buffer.appendInt32(-1392388579) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(hash, buffer: buffer, boxed: false) + serializeString(deviceModel, buffer: buffer, boxed: false) + serializeString(platform, buffer: buffer, boxed: false) + serializeString(systemVersion, buffer: buffer, boxed: false) + serializeInt32(apiId, buffer: buffer, boxed: false) + serializeString(appName, buffer: buffer, boxed: false) + serializeString(appVersion, buffer: buffer, boxed: false) + serializeInt32(dateCreated, buffer: buffer, boxed: false) + serializeInt32(dateActive, buffer: buffer, boxed: false) + serializeString(ip, buffer: buffer, boxed: false) + serializeString(country, buffer: buffer, boxed: false) + serializeString(region, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .authorization(let flags, let hash, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let dateCreated, let dateActive, let ip, let country, let region): + return ("authorization", [("flags", flags), ("hash", hash), ("deviceModel", deviceModel), ("platform", platform), ("systemVersion", systemVersion), ("apiId", apiId), ("appName", appName), ("appVersion", appVersion), ("dateCreated", dateCreated), ("dateActive", dateActive), ("ip", ip), ("country", country), ("region", region)]) + } + } + + static func parse_authorization(_ reader: BufferReader) -> Authorization? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: String? + _7 = parseString(reader) + var _8: String? + _8 = parseString(reader) + var _9: Int32? + _9 = reader.readInt32() + var _10: Int32? + _10 = reader.readInt32() + var _11: String? + _11 = parseString(reader) + var _12: String? + _12 = parseString(reader) + var _13: String? + _13 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.Authorization.authorization(flags: _1!, hash: _2!, deviceModel: _3!, platform: _4!, systemVersion: _5!, apiId: _6!, appName: _7!, appVersion: _8!, dateCreated: _9!, dateActive: _10!, ip: _11!, country: _12!, region: _13!) + } + else { + return nil + } + } + + } + enum MaskCoords: TypeConstructorDescription { + case maskCoords(n: Int32, x: Double, y: Double, zoom: Double) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .maskCoords(let n, let x, let y, let zoom): + if boxed { + buffer.appendInt32(-1361650766) + } + serializeInt32(n, buffer: buffer, boxed: false) + serializeDouble(x, buffer: buffer, boxed: false) + serializeDouble(y, buffer: buffer, boxed: false) + serializeDouble(zoom, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .maskCoords(let n, let x, let y, let zoom): + return ("maskCoords", [("n", n), ("x", x), ("y", y), ("zoom", zoom)]) + } + } + + static func parse_maskCoords(_ reader: BufferReader) -> MaskCoords? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Double? + _2 = reader.readDouble() + var _3: Double? + _3 = reader.readDouble() + var _4: Double? + _4 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.MaskCoords.maskCoords(n: _1!, x: _2!, y: _3!, zoom: _4!) + } + else { + return nil + } + } + + } + enum PhoneConnection: TypeConstructorDescription { + case phoneConnection(id: Int64, ip: String, ipv6: String, port: Int32, peerTag: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .phoneConnection(let id, let ip, let ipv6, let port, let peerTag): + if boxed { + buffer.appendInt32(-1655957568) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeString(ip, buffer: buffer, boxed: false) + serializeString(ipv6, buffer: buffer, boxed: false) + serializeInt32(port, buffer: buffer, boxed: false) + serializeBytes(peerTag, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .phoneConnection(let id, let ip, let ipv6, let port, let peerTag): + return ("phoneConnection", [("id", id), ("ip", ip), ("ipv6", ipv6), ("port", port), ("peerTag", peerTag)]) + } + } + + static func parse_phoneConnection(_ reader: BufferReader) -> PhoneConnection? { + var _1: Int64? + _1 = reader.readInt64() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PhoneConnection.phoneConnection(id: _1!, ip: _2!, ipv6: _3!, port: _4!, peerTag: _5!) + } + else { + return nil + } + } + + } + enum AccountDaysTTL: TypeConstructorDescription { + case accountDaysTTL(days: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .accountDaysTTL(let days): + if boxed { + buffer.appendInt32(-1194283041) + } + serializeInt32(days, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .accountDaysTTL(let days): + return ("accountDaysTTL", [("days", days)]) + } + } + + static func parse_accountDaysTTL(_ reader: BufferReader) -> AccountDaysTTL? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.AccountDaysTTL.accountDaysTTL(days: _1!) + } + else { + return nil + } + } + + } + enum SecureValueType: TypeConstructorDescription { + case secureValueTypePersonalDetails + case secureValueTypePassport + case secureValueTypeDriverLicense + case secureValueTypeIdentityCard + case secureValueTypeInternalPassport + case secureValueTypeAddress + case secureValueTypeUtilityBill + case secureValueTypeBankStatement + case secureValueTypeRentalAgreement + case secureValueTypePassportRegistration + case secureValueTypeTemporaryRegistration + case secureValueTypePhone + case secureValueTypeEmail + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValueTypePersonalDetails: + if boxed { + buffer.appendInt32(-1658158621) + } + + break + case .secureValueTypePassport: + if boxed { + buffer.appendInt32(1034709504) + } + + break + case .secureValueTypeDriverLicense: + if boxed { + buffer.appendInt32(115615172) + } + + break + case .secureValueTypeIdentityCard: + if boxed { + buffer.appendInt32(-1596951477) + } + + break + case .secureValueTypeInternalPassport: + if boxed { + buffer.appendInt32(-1717268701) + } + + break + case .secureValueTypeAddress: + if boxed { + buffer.appendInt32(-874308058) + } + + break + case .secureValueTypeUtilityBill: + if boxed { + buffer.appendInt32(-63531698) + } + + break + case .secureValueTypeBankStatement: + if boxed { + buffer.appendInt32(-1995211763) + } + + break + case .secureValueTypeRentalAgreement: + if boxed { + buffer.appendInt32(-1954007928) + } + + break + case .secureValueTypePassportRegistration: + if boxed { + buffer.appendInt32(-1713143702) + } + + break + case .secureValueTypeTemporaryRegistration: + if boxed { + buffer.appendInt32(-368907213) + } + + break + case .secureValueTypePhone: + if boxed { + buffer.appendInt32(-1289704741) + } + + break + case .secureValueTypeEmail: + if boxed { + buffer.appendInt32(-1908627474) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureValueTypePersonalDetails: + return ("secureValueTypePersonalDetails", []) + case .secureValueTypePassport: + return ("secureValueTypePassport", []) + case .secureValueTypeDriverLicense: + return ("secureValueTypeDriverLicense", []) + case .secureValueTypeIdentityCard: + return ("secureValueTypeIdentityCard", []) + case .secureValueTypeInternalPassport: + return ("secureValueTypeInternalPassport", []) + case .secureValueTypeAddress: + return ("secureValueTypeAddress", []) + case .secureValueTypeUtilityBill: + return ("secureValueTypeUtilityBill", []) + case .secureValueTypeBankStatement: + return ("secureValueTypeBankStatement", []) + case .secureValueTypeRentalAgreement: + return ("secureValueTypeRentalAgreement", []) + case .secureValueTypePassportRegistration: + return ("secureValueTypePassportRegistration", []) + case .secureValueTypeTemporaryRegistration: + return ("secureValueTypeTemporaryRegistration", []) + case .secureValueTypePhone: + return ("secureValueTypePhone", []) + case .secureValueTypeEmail: + return ("secureValueTypeEmail", []) + } + } + + static func parse_secureValueTypePersonalDetails(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypePersonalDetails + } + static func parse_secureValueTypePassport(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypePassport + } + static func parse_secureValueTypeDriverLicense(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeDriverLicense + } + static func parse_secureValueTypeIdentityCard(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeIdentityCard + } + static func parse_secureValueTypeInternalPassport(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeInternalPassport + } + static func parse_secureValueTypeAddress(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeAddress + } + static func parse_secureValueTypeUtilityBill(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeUtilityBill + } + static func parse_secureValueTypeBankStatement(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeBankStatement + } + static func parse_secureValueTypeRentalAgreement(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeRentalAgreement + } + static func parse_secureValueTypePassportRegistration(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypePassportRegistration + } + static func parse_secureValueTypeTemporaryRegistration(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeTemporaryRegistration + } + static func parse_secureValueTypePhone(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypePhone + } + static func parse_secureValueTypeEmail(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeEmail + } + + } + enum PasswordKdfAlgo: TypeConstructorDescription { + case passwordKdfAlgoUnknown + case passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: Buffer, salt2: Buffer, g: Int32, p: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .passwordKdfAlgoUnknown: + if boxed { + buffer.appendInt32(-732254058) + } + + break + case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(let salt1, let salt2, let g, let p): + if boxed { + buffer.appendInt32(982592842) + } + serializeBytes(salt1, buffer: buffer, boxed: false) + serializeBytes(salt2, buffer: buffer, boxed: false) + serializeInt32(g, buffer: buffer, boxed: false) + serializeBytes(p, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .passwordKdfAlgoUnknown: + return ("passwordKdfAlgoUnknown", []) + case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(let salt1, let salt2, let g, let p): + return ("passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow", [("salt1", salt1), ("salt2", salt2), ("g", g), ("p", p)]) + } + } + + static func parse_passwordKdfAlgoUnknown(_ reader: BufferReader) -> PasswordKdfAlgo? { + return Api.PasswordKdfAlgo.passwordKdfAlgoUnknown + } + static func parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(_ reader: BufferReader) -> PasswordKdfAlgo? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: _1!, salt2: _2!, g: _3!, p: _4!) + } + else { + return nil + } + } + + } + enum InputBotInlineResult: TypeConstructorDescription { + case inputBotInlineResultPhoto(id: String, type: String, photo: Api.InputPhoto, sendMessage: Api.InputBotInlineMessage) + case inputBotInlineResultDocument(flags: Int32, id: String, type: String, title: String?, description: String?, document: Api.InputDocument, sendMessage: Api.InputBotInlineMessage) + case inputBotInlineResultGame(id: String, shortName: String, sendMessage: Api.InputBotInlineMessage) + case inputBotInlineResult(flags: Int32, id: String, type: String, title: String?, description: String?, url: String?, thumb: Api.InputWebDocument?, content: Api.InputWebDocument?, sendMessage: Api.InputBotInlineMessage) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBotInlineResultPhoto(let id, let type, let photo, let sendMessage): + if boxed { + buffer.appendInt32(-1462213465) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + sendMessage.serialize(buffer, true) + break + case .inputBotInlineResultDocument(let flags, let id, let type, let title, let description, let document, let sendMessage): + if boxed { + buffer.appendInt32(-459324) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + document.serialize(buffer, true) + sendMessage.serialize(buffer, true) + break + case .inputBotInlineResultGame(let id, let shortName, let sendMessage): + if boxed { + buffer.appendInt32(1336154098) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(shortName, buffer: buffer, boxed: false) + sendMessage.serialize(buffer, true) + break + case .inputBotInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + if boxed { + buffer.appendInt32(-2000710887) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {content!.serialize(buffer, true)} + sendMessage.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBotInlineResultPhoto(let id, let type, let photo, let sendMessage): + return ("inputBotInlineResultPhoto", [("id", id), ("type", type), ("photo", photo), ("sendMessage", sendMessage)]) + case .inputBotInlineResultDocument(let flags, let id, let type, let title, let description, let document, let sendMessage): + return ("inputBotInlineResultDocument", [("flags", flags), ("id", id), ("type", type), ("title", title), ("description", description), ("document", document), ("sendMessage", sendMessage)]) + case .inputBotInlineResultGame(let id, let shortName, let sendMessage): + return ("inputBotInlineResultGame", [("id", id), ("shortName", shortName), ("sendMessage", sendMessage)]) + case .inputBotInlineResult(let flags, let id, let type, let title, let description, let url, let thumb, let content, let sendMessage): + return ("inputBotInlineResult", [("flags", flags), ("id", id), ("type", type), ("title", title), ("description", description), ("url", url), ("thumb", thumb), ("content", content), ("sendMessage", sendMessage)]) + } + } + + static func parse_inputBotInlineResultPhoto(_ reader: BufferReader) -> InputBotInlineResult? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: Api.InputPhoto? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.InputPhoto + } + var _4: Api.InputBotInlineMessage? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputBotInlineResult.inputBotInlineResultPhoto(id: _1!, type: _2!, photo: _3!, sendMessage: _4!) + } + else { + return nil + } + } + static func parse_inputBotInlineResultDocument(_ reader: BufferReader) -> InputBotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: Api.InputDocument? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.InputDocument + } + var _7: Api.InputBotInlineMessage? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.InputBotInlineResult.inputBotInlineResultDocument(flags: _1!, id: _2!, type: _3!, title: _4, description: _5, document: _6!, sendMessage: _7!) + } + else { + return nil + } + } + static func parse_inputBotInlineResultGame(_ reader: BufferReader) -> InputBotInlineResult? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: Api.InputBotInlineMessage? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputBotInlineResult.inputBotInlineResultGame(id: _1!, shortName: _2!, sendMessage: _3!) + } + else { + return nil + } + } + static func parse_inputBotInlineResult(_ reader: BufferReader) -> InputBotInlineResult? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _7: Api.InputWebDocument? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.InputWebDocument + } } + var _8: Api.InputWebDocument? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.InputWebDocument + } } + var _9: Api.InputBotInlineMessage? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.InputBotInlineMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.InputBotInlineResult.inputBotInlineResult(flags: _1!, id: _2!, type: _3!, title: _4, description: _5, url: _6, thumb: _7, content: _8, sendMessage: _9!) + } + else { + return nil + } + } + + } + enum PrivacyRule: TypeConstructorDescription { + case privacyValueAllowContacts + case privacyValueAllowAll + case privacyValueAllowUsers(users: [Int32]) + case privacyValueDisallowContacts + case privacyValueDisallowAll + case privacyValueDisallowUsers(users: [Int32]) + case privacyValueAllowChatParticipants(chats: [Int32]) + case privacyValueDisallowChatParticipants(chats: [Int32]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .privacyValueAllowContacts: + if boxed { + buffer.appendInt32(-123988) + } + + break + case .privacyValueAllowAll: + if boxed { + buffer.appendInt32(1698855810) + } + + break + case .privacyValueAllowUsers(let users): + if boxed { + buffer.appendInt32(1297858060) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .privacyValueDisallowContacts: + if boxed { + buffer.appendInt32(-125240806) + } + + break + case .privacyValueDisallowAll: + if boxed { + buffer.appendInt32(-1955338397) + } + + break + case .privacyValueDisallowUsers(let users): + if boxed { + buffer.appendInt32(209668535) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .privacyValueAllowChatParticipants(let chats): + if boxed { + buffer.appendInt32(415136107) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .privacyValueDisallowChatParticipants(let chats): + if boxed { + buffer.appendInt32(-1397881200) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .privacyValueAllowContacts: + return ("privacyValueAllowContacts", []) + case .privacyValueAllowAll: + return ("privacyValueAllowAll", []) + case .privacyValueAllowUsers(let users): + return ("privacyValueAllowUsers", [("users", users)]) + case .privacyValueDisallowContacts: + return ("privacyValueDisallowContacts", []) + case .privacyValueDisallowAll: + return ("privacyValueDisallowAll", []) + case .privacyValueDisallowUsers(let users): + return ("privacyValueDisallowUsers", [("users", users)]) + case .privacyValueAllowChatParticipants(let chats): + return ("privacyValueAllowChatParticipants", [("chats", chats)]) + case .privacyValueDisallowChatParticipants(let chats): + return ("privacyValueDisallowChatParticipants", [("chats", chats)]) + } + } + + static func parse_privacyValueAllowContacts(_ reader: BufferReader) -> PrivacyRule? { + return Api.PrivacyRule.privacyValueAllowContacts + } + static func parse_privacyValueAllowAll(_ reader: BufferReader) -> PrivacyRule? { + return Api.PrivacyRule.privacyValueAllowAll + } + static func parse_privacyValueAllowUsers(_ reader: BufferReader) -> PrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PrivacyRule.privacyValueAllowUsers(users: _1!) + } + else { + return nil + } + } + static func parse_privacyValueDisallowContacts(_ reader: BufferReader) -> PrivacyRule? { + return Api.PrivacyRule.privacyValueDisallowContacts + } + static func parse_privacyValueDisallowAll(_ reader: BufferReader) -> PrivacyRule? { + return Api.PrivacyRule.privacyValueDisallowAll + } + static func parse_privacyValueDisallowUsers(_ reader: BufferReader) -> PrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PrivacyRule.privacyValueDisallowUsers(users: _1!) + } + else { + return nil + } + } + static func parse_privacyValueAllowChatParticipants(_ reader: BufferReader) -> PrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PrivacyRule.privacyValueAllowChatParticipants(chats: _1!) + } + else { + return nil + } + } + static func parse_privacyValueDisallowChatParticipants(_ reader: BufferReader) -> PrivacyRule? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.PrivacyRule.privacyValueDisallowChatParticipants(chats: _1!) + } + else { + return nil + } + } + + } + enum MessageAction: TypeConstructorDescription { + case messageActionEmpty + case messageActionChatCreate(title: String, users: [Int32]) + case messageActionChatEditTitle(title: String) + case messageActionChatEditPhoto(photo: Api.Photo) + case messageActionChatDeletePhoto + case messageActionChatAddUser(users: [Int32]) + case messageActionChatDeleteUser(userId: Int32) + case messageActionChatJoinedByLink(inviterId: Int32) + case messageActionChannelCreate(title: String) + case messageActionChatMigrateTo(channelId: Int32) + case messageActionChannelMigrateFrom(title: String, chatId: Int32) + case messageActionPinMessage + case messageActionHistoryClear + case messageActionGameScore(gameId: Int64, score: Int32) + case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge) + case messageActionPaymentSent(currency: String, totalAmount: Int64) + case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?) + case messageActionScreenshotTaken + case messageActionCustomAction(message: String) + case messageActionBotAllowed(domain: String) + case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) + case messageActionSecureValuesSent(types: [Api.SecureValueType]) + case messageActionContactSignUp + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageActionEmpty: + if boxed { + buffer.appendInt32(-1230047312) + } + + break + case .messageActionChatCreate(let title, let users): + if boxed { + buffer.appendInt32(-1503425638) + } + serializeString(title, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .messageActionChatEditTitle(let title): + if boxed { + buffer.appendInt32(-1247687078) + } + serializeString(title, buffer: buffer, boxed: false) + break + case .messageActionChatEditPhoto(let photo): + if boxed { + buffer.appendInt32(2144015272) + } + photo.serialize(buffer, true) + break + case .messageActionChatDeletePhoto: + if boxed { + buffer.appendInt32(-1780220945) + } + + break + case .messageActionChatAddUser(let users): + if boxed { + buffer.appendInt32(1217033015) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .messageActionChatDeleteUser(let userId): + if boxed { + buffer.appendInt32(-1297179892) + } + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .messageActionChatJoinedByLink(let inviterId): + if boxed { + buffer.appendInt32(-123931160) + } + serializeInt32(inviterId, buffer: buffer, boxed: false) + break + case .messageActionChannelCreate(let title): + if boxed { + buffer.appendInt32(-1781355374) + } + serializeString(title, buffer: buffer, boxed: false) + break + case .messageActionChatMigrateTo(let channelId): + if boxed { + buffer.appendInt32(1371385889) + } + serializeInt32(channelId, buffer: buffer, boxed: false) + break + case .messageActionChannelMigrateFrom(let title, let chatId): + if boxed { + buffer.appendInt32(-1336546578) + } + serializeString(title, buffer: buffer, boxed: false) + serializeInt32(chatId, buffer: buffer, boxed: false) + break + case .messageActionPinMessage: + if boxed { + buffer.appendInt32(-1799538451) + } + + break + case .messageActionHistoryClear: + if boxed { + buffer.appendInt32(-1615153660) + } + + break + case .messageActionGameScore(let gameId, let score): + if boxed { + buffer.appendInt32(-1834538890) + } + serializeInt64(gameId, buffer: buffer, boxed: false) + serializeInt32(score, buffer: buffer, boxed: false) + break + case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge): + if boxed { + buffer.appendInt32(-1892568281) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(currency, buffer: buffer, boxed: false) + serializeInt64(totalAmount, buffer: buffer, boxed: false) + serializeBytes(payload, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {info!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(shippingOptionId!, buffer: buffer, boxed: false)} + charge.serialize(buffer, true) + break + case .messageActionPaymentSent(let currency, let totalAmount): + if boxed { + buffer.appendInt32(1080663248) + } + serializeString(currency, buffer: buffer, boxed: false) + serializeInt64(totalAmount, buffer: buffer, boxed: false) + break + case .messageActionPhoneCall(let flags, let callId, let reason, let duration): + if boxed { + buffer.appendInt32(-2132731265) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(callId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {reason!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)} + break + case .messageActionScreenshotTaken: + if boxed { + buffer.appendInt32(1200788123) + } + + break + case .messageActionCustomAction(let message): + if boxed { + buffer.appendInt32(-85549226) + } + serializeString(message, buffer: buffer, boxed: false) + break + case .messageActionBotAllowed(let domain): + if boxed { + buffer.appendInt32(-1410748418) + } + serializeString(domain, buffer: buffer, boxed: false) + break + case .messageActionSecureValuesSentMe(let values, let credentials): + if boxed { + buffer.appendInt32(455635795) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(values.count)) + for item in values { + item.serialize(buffer, true) + } + credentials.serialize(buffer, true) + break + case .messageActionSecureValuesSent(let types): + if boxed { + buffer.appendInt32(-648257196) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) + } + break + case .messageActionContactSignUp: + if boxed { + buffer.appendInt32(-202219658) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageActionEmpty: + return ("messageActionEmpty", []) + case .messageActionChatCreate(let title, let users): + return ("messageActionChatCreate", [("title", title), ("users", users)]) + case .messageActionChatEditTitle(let title): + return ("messageActionChatEditTitle", [("title", title)]) + case .messageActionChatEditPhoto(let photo): + return ("messageActionChatEditPhoto", [("photo", photo)]) + case .messageActionChatDeletePhoto: + return ("messageActionChatDeletePhoto", []) + case .messageActionChatAddUser(let users): + return ("messageActionChatAddUser", [("users", users)]) + case .messageActionChatDeleteUser(let userId): + return ("messageActionChatDeleteUser", [("userId", userId)]) + case .messageActionChatJoinedByLink(let inviterId): + return ("messageActionChatJoinedByLink", [("inviterId", inviterId)]) + case .messageActionChannelCreate(let title): + return ("messageActionChannelCreate", [("title", title)]) + case .messageActionChatMigrateTo(let channelId): + return ("messageActionChatMigrateTo", [("channelId", channelId)]) + case .messageActionChannelMigrateFrom(let title, let chatId): + return ("messageActionChannelMigrateFrom", [("title", title), ("chatId", chatId)]) + case .messageActionPinMessage: + return ("messageActionPinMessage", []) + case .messageActionHistoryClear: + return ("messageActionHistoryClear", []) + case .messageActionGameScore(let gameId, let score): + return ("messageActionGameScore", [("gameId", gameId), ("score", score)]) + case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge): + return ("messageActionPaymentSentMe", [("flags", flags), ("currency", currency), ("totalAmount", totalAmount), ("payload", payload), ("info", info), ("shippingOptionId", shippingOptionId), ("charge", charge)]) + case .messageActionPaymentSent(let currency, let totalAmount): + return ("messageActionPaymentSent", [("currency", currency), ("totalAmount", totalAmount)]) + case .messageActionPhoneCall(let flags, let callId, let reason, let duration): + return ("messageActionPhoneCall", [("flags", flags), ("callId", callId), ("reason", reason), ("duration", duration)]) + case .messageActionScreenshotTaken: + return ("messageActionScreenshotTaken", []) + case .messageActionCustomAction(let message): + return ("messageActionCustomAction", [("message", message)]) + case .messageActionBotAllowed(let domain): + return ("messageActionBotAllowed", [("domain", domain)]) + case .messageActionSecureValuesSentMe(let values, let credentials): + return ("messageActionSecureValuesSentMe", [("values", values), ("credentials", credentials)]) + case .messageActionSecureValuesSent(let types): + return ("messageActionSecureValuesSent", [("types", types)]) + case .messageActionContactSignUp: + return ("messageActionContactSignUp", []) + } + } + + static func parse_messageActionEmpty(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionEmpty + } + static func parse_messageActionChatCreate(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + var _2: [Int32]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageAction.messageActionChatCreate(title: _1!, users: _2!) + } + else { + return nil + } + } + static func parse_messageActionChatEditTitle(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatEditTitle(title: _1!) + } + else { + return nil + } + } + static func parse_messageActionChatEditPhoto(_ reader: BufferReader) -> MessageAction? { + var _1: Api.Photo? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Photo + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatEditPhoto(photo: _1!) + } + else { + return nil + } + } + static func parse_messageActionChatDeletePhoto(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionChatDeletePhoto + } + static func parse_messageActionChatAddUser(_ reader: BufferReader) -> MessageAction? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatAddUser(users: _1!) + } + else { + return nil + } + } + static func parse_messageActionChatDeleteUser(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatDeleteUser(userId: _1!) + } + else { + return nil + } + } + static func parse_messageActionChatJoinedByLink(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatJoinedByLink(inviterId: _1!) + } + else { + return nil + } + } + static func parse_messageActionChannelCreate(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChannelCreate(title: _1!) + } + else { + return nil + } + } + static func parse_messageActionChatMigrateTo(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionChatMigrateTo(channelId: _1!) + } + else { + return nil + } + } + static func parse_messageActionChannelMigrateFrom(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageAction.messageActionChannelMigrateFrom(title: _1!, chatId: _2!) + } + else { + return nil + } + } + static func parse_messageActionPinMessage(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionPinMessage + } + static func parse_messageActionHistoryClear(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionHistoryClear + } + static func parse_messageActionGameScore(_ reader: BufferReader) -> MessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageAction.messageActionGameScore(gameId: _1!, score: _2!) + } + else { + return nil + } + } + static func parse_messageActionPaymentSentMe(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int64? + _3 = reader.readInt64() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + var _6: String? + if Int(_1!) & Int(1 << 1) != 0 {_6 = parseString(reader) } + var _7: Api.PaymentCharge? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PaymentCharge + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.MessageAction.messageActionPaymentSentMe(flags: _1!, currency: _2!, totalAmount: _3!, payload: _4!, info: _5, shippingOptionId: _6, charge: _7!) + } + else { + return nil + } + } + static func parse_messageActionPaymentSent(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageAction.messageActionPaymentSent(currency: _1!, totalAmount: _2!) + } + else { + return nil + } + } + static func parse_messageActionPhoneCall(_ reader: BufferReader) -> MessageAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.PhoneCallDiscardReason? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.PhoneCallDiscardReason + } } + var _4: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.MessageAction.messageActionPhoneCall(flags: _1!, callId: _2!, reason: _3, duration: _4) + } + else { + return nil + } + } + static func parse_messageActionScreenshotTaken(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionScreenshotTaken + } + static func parse_messageActionCustomAction(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionCustomAction(message: _1!) + } + else { + return nil + } + } + static func parse_messageActionBotAllowed(_ reader: BufferReader) -> MessageAction? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionBotAllowed(domain: _1!) + } + else { + return nil + } + } + static func parse_messageActionSecureValuesSentMe(_ reader: BufferReader) -> MessageAction? { + var _1: [Api.SecureValue]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) + } + var _2: Api.SecureCredentialsEncrypted? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureCredentialsEncrypted + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageAction.messageActionSecureValuesSentMe(values: _1!, credentials: _2!) + } + else { + return nil + } + } + static func parse_messageActionSecureValuesSent(_ reader: BufferReader) -> MessageAction? { + var _1: [Api.SecureValueType]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValueType.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.MessageAction.messageActionSecureValuesSent(types: _1!) + } + else { + return nil + } + } + static func parse_messageActionContactSignUp(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionContactSignUp + } + + } + enum PhoneCall: TypeConstructorDescription { + case phoneCallEmpty(id: Int64) + case phoneCallWaiting(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, protocol: Api.PhoneCallProtocol, receiveDate: Int32?) + case phoneCallRequested(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, gAHash: Buffer, protocol: Api.PhoneCallProtocol) + case phoneCallAccepted(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, gB: Buffer, protocol: Api.PhoneCallProtocol) + case phoneCall(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, gAOrB: Buffer, keyFingerprint: Int64, protocol: Api.PhoneCallProtocol, connections: [Api.PhoneConnection], startDate: Int32) + case phoneCallDiscarded(flags: Int32, id: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .phoneCallEmpty(let id): + if boxed { + buffer.appendInt32(1399245077) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate): + if boxed { + buffer.appendInt32(462375633) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(receiveDate!, buffer: buffer, boxed: false)} + break + case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`): + if boxed { + buffer.appendInt32(-2014659757) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + serializeBytes(gAHash, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + break + case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`): + if boxed { + buffer.appendInt32(-1719909046) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + serializeBytes(gB, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + break + case .phoneCall(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint, let `protocol`, let connections, let startDate): + if boxed { + buffer.appendInt32(-2025673089) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + serializeBytes(gAOrB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(connections.count)) + for item in connections { + item.serialize(buffer, true) + } + serializeInt32(startDate, buffer: buffer, boxed: false) + break + case .phoneCallDiscarded(let flags, let id, let reason, let duration): + if boxed { + buffer.appendInt32(1355435489) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {reason!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .phoneCallEmpty(let id): + return ("phoneCallEmpty", [("id", id)]) + case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate): + return ("phoneCallWaiting", [("flags", flags), ("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("`protocol`", `protocol`), ("receiveDate", receiveDate)]) + case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`): + return ("phoneCallRequested", [("flags", flags), ("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("gAHash", gAHash), ("`protocol`", `protocol`)]) + case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`): + return ("phoneCallAccepted", [("flags", flags), ("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("gB", gB), ("`protocol`", `protocol`)]) + case .phoneCall(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint, let `protocol`, let connections, let startDate): + return ("phoneCall", [("flags", flags), ("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("gAOrB", gAOrB), ("keyFingerprint", keyFingerprint), ("`protocol`", `protocol`), ("connections", connections), ("startDate", startDate)]) + case .phoneCallDiscarded(let flags, let id, let reason, let duration): + return ("phoneCallDiscarded", [("flags", flags), ("id", id), ("reason", reason), ("duration", duration)]) + } + } + + static func parse_phoneCallEmpty(_ reader: BufferReader) -> PhoneCall? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.PhoneCall.phoneCallEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_phoneCallWaiting(_ reader: BufferReader) -> PhoneCall? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Api.PhoneCallProtocol? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol + } + var _8: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_8 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.PhoneCall.phoneCallWaiting(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, protocol: _7!, receiveDate: _8) + } + else { + return nil + } + } + static func parse_phoneCallRequested(_ reader: BufferReader) -> PhoneCall? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Api.PhoneCallProtocol? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.PhoneCall.phoneCallRequested(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gAHash: _7!, protocol: _8!) + } + else { + return nil + } + } + static func parse_phoneCallAccepted(_ reader: BufferReader) -> PhoneCall? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Api.PhoneCallProtocol? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.PhoneCall.phoneCallAccepted(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gB: _7!, protocol: _8!) + } + else { + return nil + } + } + static func parse_phoneCall(_ reader: BufferReader) -> PhoneCall? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Int64? + _8 = reader.readInt64() + var _9: Api.PhoneCallProtocol? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol + } + var _10: [Api.PhoneConnection]? + if let _ = reader.readInt32() { + _10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhoneConnection.self) + } + var _11: Int32? + _11 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return Api.PhoneCall.phoneCall(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gAOrB: _7!, keyFingerprint: _8!, protocol: _9!, connections: _10!, startDate: _11!) + } + else { + return nil + } + } + static func parse_phoneCallDiscarded(_ reader: BufferReader) -> PhoneCall? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.PhoneCallDiscardReason? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.PhoneCallDiscardReason + } } + var _4: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.PhoneCall.phoneCallDiscarded(flags: _1!, id: _2!, reason: _3, duration: _4) + } + else { + return nil + } + } + + } + enum DialogPeer: TypeConstructorDescription { + case dialogPeer(peer: Api.Peer) + case dialogPeerFolder(folderId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dialogPeer(let peer): + if boxed { + buffer.appendInt32(-445792507) + } + peer.serialize(buffer, true) + break + case .dialogPeerFolder(let folderId): + if boxed { + buffer.appendInt32(1363483106) + } + serializeInt32(folderId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dialogPeer(let peer): + return ("dialogPeer", [("peer", peer)]) + case .dialogPeerFolder(let folderId): + return ("dialogPeerFolder", [("folderId", folderId)]) + } + } + + static func parse_dialogPeer(_ reader: BufferReader) -> DialogPeer? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + let _c1 = _1 != nil + if _c1 { + return Api.DialogPeer.dialogPeer(peer: _1!) + } + else { + return nil + } + } + static func parse_dialogPeerFolder(_ reader: BufferReader) -> DialogPeer? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.DialogPeer.dialogPeerFolder(folderId: _1!) + } + else { + return nil + } + } + + } + enum ContactLink: TypeConstructorDescription { + case contactLinkUnknown + case contactLinkNone + case contactLinkContact + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contactLinkUnknown: + if boxed { + buffer.appendInt32(1599050311) + } + + break + case .contactLinkNone: + if boxed { + buffer.appendInt32(-17968211) + } + + break + case .contactLinkContact: + if boxed { + buffer.appendInt32(-721239344) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contactLinkUnknown: + return ("contactLinkUnknown", []) + case .contactLinkNone: + return ("contactLinkNone", []) + case .contactLinkContact: + return ("contactLinkContact", []) + } + } + + static func parse_contactLinkUnknown(_ reader: BufferReader) -> ContactLink? { + return Api.ContactLink.contactLinkUnknown + } + static func parse_contactLinkNone(_ reader: BufferReader) -> ContactLink? { + return Api.ContactLink.contactLinkNone + } + static func parse_contactLinkContact(_ reader: BufferReader) -> ContactLink? { + return Api.ContactLink.contactLinkContact + } + + } + enum WebDocument: TypeConstructorDescription { + case webDocumentNoProxy(url: String, size: Int32, mimeType: String, attributes: [Api.DocumentAttribute]) + case webDocument(url: String, accessHash: Int64, size: Int32, mimeType: String, attributes: [Api.DocumentAttribute]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .webDocumentNoProxy(let url, let size, let mimeType, let attributes): + if boxed { + buffer.appendInt32(-104284986) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + case .webDocument(let url, let accessHash, let size, let mimeType, let attributes): + if boxed { + buffer.appendInt32(475467473) + } + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .webDocumentNoProxy(let url, let size, let mimeType, let attributes): + return ("webDocumentNoProxy", [("url", url), ("size", size), ("mimeType", mimeType), ("attributes", attributes)]) + case .webDocument(let url, let accessHash, let size, let mimeType, let attributes): + return ("webDocument", [("url", url), ("accessHash", accessHash), ("size", size), ("mimeType", mimeType), ("attributes", attributes)]) + } + } + + static func parse_webDocumentNoProxy(_ reader: BufferReader) -> WebDocument? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.WebDocument.webDocumentNoProxy(url: _1!, size: _2!, mimeType: _3!, attributes: _4!) + } + else { + return nil + } + } + static func parse_webDocument(_ reader: BufferReader) -> WebDocument? { + var _1: String? + _1 = parseString(reader) + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.WebDocument.webDocument(url: _1!, accessHash: _2!, size: _3!, mimeType: _4!, attributes: _5!) + } + else { + return nil + } + } + + } + enum ChannelAdminLogEventsFilter: TypeConstructorDescription { + case channelAdminLogEventsFilter(flags: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelAdminLogEventsFilter(let flags): + if boxed { + buffer.appendInt32(-368018716) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelAdminLogEventsFilter(let flags): + return ("channelAdminLogEventsFilter", [("flags", flags)]) + } + } + + static func parse_channelAdminLogEventsFilter(_ reader: BufferReader) -> ChannelAdminLogEventsFilter? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: _1!) + } + else { + return nil + } + } + + } + enum PeerNotifySettings: TypeConstructorDescription { + case peerNotifySettingsEmpty + case peerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: String?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .peerNotifySettingsEmpty: + if boxed { + buffer.appendInt32(1889961234) + } + + break + case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): + if boxed { + buffer.appendInt32(-1353671392) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {showPreviews!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {silent!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(muteUntil!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(sound!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .peerNotifySettingsEmpty: + return ("peerNotifySettingsEmpty", []) + case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): + return ("peerNotifySettings", [("flags", flags), ("showPreviews", showPreviews), ("silent", silent), ("muteUntil", muteUntil), ("sound", sound)]) + } + } + + static func parse_peerNotifySettingsEmpty(_ reader: BufferReader) -> PeerNotifySettings? { + return Api.PeerNotifySettings.peerNotifySettingsEmpty + } + static func parse_peerNotifySettings(_ reader: BufferReader) -> PeerNotifySettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Bool? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Bool + } } + var _3: Api.Bool? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Bool + } } + var _4: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.PeerNotifySettings.peerNotifySettings(flags: _1!, showPreviews: _2, silent: _3, muteUntil: _4, sound: _5) + } + else { + return nil + } + } + + } + enum InputBotInlineMessageID: TypeConstructorDescription { + case inputBotInlineMessageID(dcId: Int32, id: Int64, accessHash: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBotInlineMessageID(let dcId, let id, let accessHash): + if boxed { + buffer.appendInt32(-1995686519) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBotInlineMessageID(let dcId, let id, let accessHash): + return ("inputBotInlineMessageID", [("dcId", dcId), ("id", id), ("accessHash", accessHash)]) + } + } + + static func parse_inputBotInlineMessageID(_ reader: BufferReader) -> InputBotInlineMessageID? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputBotInlineMessageID.inputBotInlineMessageID(dcId: _1!, id: _2!, accessHash: _3!) + } + else { + return nil + } + } + + } + enum PageRelatedArticle: TypeConstructorDescription { + case pageRelatedArticle(flags: Int32, url: String, webpageId: Int64, title: String?, description: String?, photoId: Int64?, author: String?, publishedDate: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId, let author, let publishedDate): + if boxed { + buffer.appendInt32(-1282352120) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + serializeInt64(webpageId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt64(photoId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(author!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeInt32(publishedDate!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageRelatedArticle(let flags, let url, let webpageId, let title, let description, let photoId, let author, let publishedDate): + return ("pageRelatedArticle", [("flags", flags), ("url", url), ("webpageId", webpageId), ("title", title), ("description", description), ("photoId", photoId), ("author", author), ("publishedDate", publishedDate)]) + } + } + + static func parse_pageRelatedArticle(_ reader: BufferReader) -> PageRelatedArticle? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } + var _6: Int64? + if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt64() } + var _7: String? + if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) } + var _8: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_8 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.PageRelatedArticle.pageRelatedArticle(flags: _1!, url: _2!, webpageId: _3!, title: _4, description: _5, photoId: _6, author: _7, publishedDate: _8) + } + else { + return nil + } + } + + } + enum StickerPack: TypeConstructorDescription { + case stickerPack(emoticon: String, documents: [Int64]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .stickerPack(let emoticon, let documents): + if boxed { + buffer.appendInt32(313694676) + } + serializeString(emoticon, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(documents.count)) + for item in documents { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .stickerPack(let emoticon, let documents): + return ("stickerPack", [("emoticon", emoticon), ("documents", documents)]) + } + } + + static func parse_stickerPack(_ reader: BufferReader) -> StickerPack? { + var _1: String? + _1 = parseString(reader) + var _2: [Int64]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StickerPack.stickerPack(emoticon: _1!, documents: _2!) + } + else { + return nil + } + } + + } + enum UserProfilePhoto: TypeConstructorDescription { + case userProfilePhotoEmpty + case userProfilePhoto(photoId: Int64, photoSmall: Api.FileLocation, photoBig: Api.FileLocation, dcId: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .userProfilePhotoEmpty: + if boxed { + buffer.appendInt32(1326562017) + } + + break + case .userProfilePhoto(let photoId, let photoSmall, let photoBig, let dcId): + if boxed { + buffer.appendInt32(-321430132) + } + serializeInt64(photoId, buffer: buffer, boxed: false) + photoSmall.serialize(buffer, true) + photoBig.serialize(buffer, true) + serializeInt32(dcId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .userProfilePhotoEmpty: + return ("userProfilePhotoEmpty", []) + case .userProfilePhoto(let photoId, let photoSmall, let photoBig, let dcId): + return ("userProfilePhoto", [("photoId", photoId), ("photoSmall", photoSmall), ("photoBig", photoBig), ("dcId", dcId)]) + } + } + + static func parse_userProfilePhotoEmpty(_ reader: BufferReader) -> UserProfilePhoto? { + return Api.UserProfilePhoto.userProfilePhotoEmpty + } + static func parse_userProfilePhoto(_ reader: BufferReader) -> UserProfilePhoto? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Api.FileLocation? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _3: Api.FileLocation? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.FileLocation + } + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.UserProfilePhoto.userProfilePhoto(photoId: _1!, photoSmall: _2!, photoBig: _3!, dcId: _4!) + } + else { + return nil + } + } + + } + enum ChatOnlines: TypeConstructorDescription { + case chatOnlines(onlines: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatOnlines(let onlines): + if boxed { + buffer.appendInt32(-264117680) + } + serializeInt32(onlines, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatOnlines(let onlines): + return ("chatOnlines", [("onlines", onlines)]) + } + } + + static func parse_chatOnlines(_ reader: BufferReader) -> ChatOnlines? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.ChatOnlines.chatOnlines(onlines: _1!) + } + else { + return nil + } + } + + } + enum InputAppEvent: TypeConstructorDescription { + case inputAppEvent(time: Double, type: String, peer: Int64, data: Api.JSONValue) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputAppEvent(let time, let type, let peer, let data): + if boxed { + buffer.appendInt32(488313413) + } + serializeDouble(time, buffer: buffer, boxed: false) + serializeString(type, buffer: buffer, boxed: false) + serializeInt64(peer, buffer: buffer, boxed: false) + data.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputAppEvent(let time, let type, let peer, let data): + return ("inputAppEvent", [("time", time), ("type", type), ("peer", peer), ("data", data)]) + } + } + + static func parse_inputAppEvent(_ reader: BufferReader) -> InputAppEvent? { + var _1: Double? + _1 = reader.readDouble() + var _2: String? + _2 = parseString(reader) + var _3: Int64? + _3 = reader.readInt64() + var _4: Api.JSONValue? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.JSONValue + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputAppEvent.inputAppEvent(time: _1!, type: _2!, peer: _3!, data: _4!) + } + else { + return nil + } + } + + } + enum MessageEntity: TypeConstructorDescription { + case messageEntityUnknown(offset: Int32, length: Int32) + case messageEntityMention(offset: Int32, length: Int32) + case messageEntityHashtag(offset: Int32, length: Int32) + case messageEntityBotCommand(offset: Int32, length: Int32) + case messageEntityUrl(offset: Int32, length: Int32) + case messageEntityEmail(offset: Int32, length: Int32) + case messageEntityBold(offset: Int32, length: Int32) + case messageEntityItalic(offset: Int32, length: Int32) + case messageEntityCode(offset: Int32, length: Int32) + case messageEntityPre(offset: Int32, length: Int32, language: String) + case messageEntityTextUrl(offset: Int32, length: Int32, url: String) + case messageEntityMentionName(offset: Int32, length: Int32, userId: Int32) + case inputMessageEntityMentionName(offset: Int32, length: Int32, userId: Api.InputUser) + case messageEntityPhone(offset: Int32, length: Int32) + case messageEntityCashtag(offset: Int32, length: Int32) + case messageEntityUnderline(offset: Int32, length: Int32) + case messageEntityStrike(offset: Int32, length: Int32) + case messageEntityBlockquote(offset: Int32, length: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageEntityUnknown(let offset, let length): + if boxed { + buffer.appendInt32(-1148011883) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityMention(let offset, let length): + if boxed { + buffer.appendInt32(-100378723) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityHashtag(let offset, let length): + if boxed { + buffer.appendInt32(1868782349) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBotCommand(let offset, let length): + if boxed { + buffer.appendInt32(1827637959) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityUrl(let offset, let length): + if boxed { + buffer.appendInt32(1859134776) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityEmail(let offset, let length): + if boxed { + buffer.appendInt32(1692693954) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBold(let offset, let length): + if boxed { + buffer.appendInt32(-1117713463) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityItalic(let offset, let length): + if boxed { + buffer.appendInt32(-2106619040) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityCode(let offset, let length): + if boxed { + buffer.appendInt32(681706865) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityPre(let offset, let length, let language): + if boxed { + buffer.appendInt32(1938967520) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(language, buffer: buffer, boxed: false) + break + case .messageEntityTextUrl(let offset, let length, let url): + if boxed { + buffer.appendInt32(1990644519) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + break + case .messageEntityMentionName(let offset, let length, let userId): + if boxed { + buffer.appendInt32(892193368) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .inputMessageEntityMentionName(let offset, let length, let userId): + if boxed { + buffer.appendInt32(546203849) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + break + case .messageEntityPhone(let offset, let length): + if boxed { + buffer.appendInt32(-1687559349) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityCashtag(let offset, let length): + if boxed { + buffer.appendInt32(1280209983) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityUnderline(let offset, let length): + if boxed { + buffer.appendInt32(-1672577397) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityStrike(let offset, let length): + if boxed { + buffer.appendInt32(-1090087980) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBlockquote(let offset, let length): + if boxed { + buffer.appendInt32(34469328) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageEntityUnknown(let offset, let length): + return ("messageEntityUnknown", [("offset", offset), ("length", length)]) + case .messageEntityMention(let offset, let length): + return ("messageEntityMention", [("offset", offset), ("length", length)]) + case .messageEntityHashtag(let offset, let length): + return ("messageEntityHashtag", [("offset", offset), ("length", length)]) + case .messageEntityBotCommand(let offset, let length): + return ("messageEntityBotCommand", [("offset", offset), ("length", length)]) + case .messageEntityUrl(let offset, let length): + return ("messageEntityUrl", [("offset", offset), ("length", length)]) + case .messageEntityEmail(let offset, let length): + return ("messageEntityEmail", [("offset", offset), ("length", length)]) + case .messageEntityBold(let offset, let length): + return ("messageEntityBold", [("offset", offset), ("length", length)]) + case .messageEntityItalic(let offset, let length): + return ("messageEntityItalic", [("offset", offset), ("length", length)]) + case .messageEntityCode(let offset, let length): + return ("messageEntityCode", [("offset", offset), ("length", length)]) + case .messageEntityPre(let offset, let length, let language): + return ("messageEntityPre", [("offset", offset), ("length", length), ("language", language)]) + case .messageEntityTextUrl(let offset, let length, let url): + return ("messageEntityTextUrl", [("offset", offset), ("length", length), ("url", url)]) + case .messageEntityMentionName(let offset, let length, let userId): + return ("messageEntityMentionName", [("offset", offset), ("length", length), ("userId", userId)]) + case .inputMessageEntityMentionName(let offset, let length, let userId): + return ("inputMessageEntityMentionName", [("offset", offset), ("length", length), ("userId", userId)]) + case .messageEntityPhone(let offset, let length): + return ("messageEntityPhone", [("offset", offset), ("length", length)]) + case .messageEntityCashtag(let offset, let length): + return ("messageEntityCashtag", [("offset", offset), ("length", length)]) + case .messageEntityUnderline(let offset, let length): + return ("messageEntityUnderline", [("offset", offset), ("length", length)]) + case .messageEntityStrike(let offset, let length): + return ("messageEntityStrike", [("offset", offset), ("length", length)]) + case .messageEntityBlockquote(let offset, let length): + return ("messageEntityBlockquote", [("offset", offset), ("length", length)]) + } + } + + static func parse_messageEntityUnknown(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityUnknown(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityMention(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityMention(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityHashtag(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityHashtag(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityBotCommand(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBotCommand(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityUrl(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityEmail(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityEmail(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityBold(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBold(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityItalic(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityItalic(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityCode(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityCode(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityPre(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageEntity.messageEntityPre(offset: _1!, length: _2!, language: _3!) + } + else { + return nil + } + } + static func parse_messageEntityTextUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageEntity.messageEntityTextUrl(offset: _1!, length: _2!, url: _3!) + } + else { + return nil + } + } + static func parse_messageEntityMentionName(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageEntity.messageEntityMentionName(offset: _1!, length: _2!, userId: _3!) + } + else { + return nil + } + } + static func parse_inputMessageEntityMentionName(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.InputUser? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.InputUser + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.MessageEntity.inputMessageEntityMentionName(offset: _1!, length: _2!, userId: _3!) + } + else { + return nil + } + } + static func parse_messageEntityPhone(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityPhone(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityCashtag(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityCashtag(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityUnderline(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityUnderline(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityStrike(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityStrike(offset: _1!, length: _2!) + } + else { + return nil + } + } + static func parse_messageEntityBlockquote(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBlockquote(offset: _1!, length: _2!) + } + else { + return nil + } + } + + } + enum InputPhoto: TypeConstructorDescription { + case inputPhotoEmpty + case inputPhoto(id: Int64, accessHash: Int64, fileReference: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputPhotoEmpty: + if boxed { + buffer.appendInt32(483901197) + } + + break + case .inputPhoto(let id, let accessHash, let fileReference): + if boxed { + buffer.appendInt32(1001634122) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputPhotoEmpty: + return ("inputPhotoEmpty", []) + case .inputPhoto(let id, let accessHash, let fileReference): + return ("inputPhoto", [("id", id), ("accessHash", accessHash), ("fileReference", fileReference)]) + } + } + + static func parse_inputPhotoEmpty(_ reader: BufferReader) -> InputPhoto? { + return Api.InputPhoto.inputPhotoEmpty + } + static func parse_inputPhoto(_ reader: BufferReader) -> InputPhoto? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputPhoto.inputPhoto(id: _1!, accessHash: _2!, fileReference: _3!) + } + else { + return nil + } + } + + } + enum PageListOrderedItem: TypeConstructorDescription { + case pageListOrderedItemText(num: String, text: Api.RichText) + case pageListOrderedItemBlocks(num: String, blocks: [Api.PageBlock]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .pageListOrderedItemText(let num, let text): + if boxed { + buffer.appendInt32(1577484359) + } + serializeString(num, buffer: buffer, boxed: false) + text.serialize(buffer, true) + break + case .pageListOrderedItemBlocks(let num, let blocks): + if boxed { + buffer.appendInt32(-1730311882) + } + serializeString(num, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .pageListOrderedItemText(let num, let text): + return ("pageListOrderedItemText", [("num", num), ("text", text)]) + case .pageListOrderedItemBlocks(let num, let blocks): + return ("pageListOrderedItemBlocks", [("num", num), ("blocks", blocks)]) + } + } + + static func parse_pageListOrderedItemText(_ reader: BufferReader) -> PageListOrderedItem? { + var _1: String? + _1 = parseString(reader) + var _2: Api.RichText? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.RichText + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageListOrderedItem.pageListOrderedItemText(num: _1!, text: _2!) + } + else { + return nil + } + } + static func parse_pageListOrderedItemBlocks(_ reader: BufferReader) -> PageListOrderedItem? { + var _1: String? + _1 = parseString(reader) + var _2: [Api.PageBlock]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PageListOrderedItem.pageListOrderedItemBlocks(num: _1!, blocks: _2!) + } + else { + return nil + } + } + + } + enum EncryptedChat: TypeConstructorDescription { + case encryptedChatEmpty(id: Int32) + case encryptedChatWaiting(id: Int32, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32) + case encryptedChatRequested(id: Int32, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, gA: Buffer) + case encryptedChat(id: Int32, accessHash: Int64, date: Int32, adminId: Int32, participantId: Int32, gAOrB: Buffer, keyFingerprint: Int64) + case encryptedChatDiscarded(id: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .encryptedChatEmpty(let id): + if boxed { + buffer.appendInt32(-1417756512) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): + if boxed { + buffer.appendInt32(1006044124) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + break + case .encryptedChatRequested(let id, let accessHash, let date, let adminId, let participantId, let gA): + if boxed { + buffer.appendInt32(-931638658) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + serializeBytes(gA, buffer: buffer, boxed: false) + break + case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): + if boxed { + buffer.appendInt32(-94974410) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(adminId, buffer: buffer, boxed: false) + serializeInt32(participantId, buffer: buffer, boxed: false) + serializeBytes(gAOrB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .encryptedChatDiscarded(let id): + if boxed { + buffer.appendInt32(332848423) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .encryptedChatEmpty(let id): + return ("encryptedChatEmpty", [("id", id)]) + case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): + return ("encryptedChatWaiting", [("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId)]) + case .encryptedChatRequested(let id, let accessHash, let date, let adminId, let participantId, let gA): + return ("encryptedChatRequested", [("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("gA", gA)]) + case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): + return ("encryptedChat", [("id", id), ("accessHash", accessHash), ("date", date), ("adminId", adminId), ("participantId", participantId), ("gAOrB", gAOrB), ("keyFingerprint", keyFingerprint)]) + case .encryptedChatDiscarded(let id): + return ("encryptedChatDiscarded", [("id", id)]) + } + } + + static func parse_encryptedChatEmpty(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.EncryptedChat.encryptedChatEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_encryptedChatWaiting(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.EncryptedChat.encryptedChatWaiting(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!) + } + else { + return nil + } + } + static func parse_encryptedChatRequested(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Buffer? + _6 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.EncryptedChat.encryptedChatRequested(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!, gA: _6!) + } + else { + return nil + } + } + static func parse_encryptedChat(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Buffer? + _6 = parseBytes(reader) + var _7: Int64? + _7 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.EncryptedChat.encryptedChat(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!, gAOrB: _6!, keyFingerprint: _7!) + } + else { + return nil + } + } + static func parse_encryptedChatDiscarded(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.EncryptedChat.encryptedChatDiscarded(id: _1!) + } + else { + return nil + } + } + + } + enum Document: TypeConstructorDescription { + case documentEmpty(id: Int64) + case document(flags: Int32, id: Int64, accessHash: Int64, fileReference: Buffer, date: Int32, mimeType: String, size: Int32, thumbs: [Api.PhotoSize]?, dcId: Int32, attributes: [Api.DocumentAttribute]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .documentEmpty(let id): + if boxed { + buffer.appendInt32(922273905) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let dcId, let attributes): + if boxed { + buffer.appendInt32(-1683841855) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(thumbs!.count)) + for item in thumbs! { + item.serialize(buffer, true) + }} + serializeInt32(dcId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .documentEmpty(let id): + return ("documentEmpty", [("id", id)]) + case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let dcId, let attributes): + return ("document", [("flags", flags), ("id", id), ("accessHash", accessHash), ("fileReference", fileReference), ("date", date), ("mimeType", mimeType), ("size", size), ("thumbs", thumbs), ("dcId", dcId), ("attributes", attributes)]) + } + } + + static func parse_documentEmpty(_ reader: BufferReader) -> Document? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.Document.documentEmpty(id: _1!) + } + else { + return nil + } + } + static func parse_document(_ reader: BufferReader) -> Document? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: String? + _6 = parseString(reader) + var _7: Int32? + _7 = reader.readInt32() + var _8: [Api.PhotoSize]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhotoSize.self) + } } + var _9: Int32? + _9 = reader.readInt32() + var _10: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.Document.document(flags: _1!, id: _2!, accessHash: _3!, fileReference: _4!, date: _5!, mimeType: _6!, size: _7!, thumbs: _8, dcId: _9!, attributes: _10!) + } + else { + return nil + } + } + + } + enum WebAuthorization: TypeConstructorDescription { + case webAuthorization(hash: Int64, botId: Int32, domain: String, browser: String, platform: String, dateCreated: Int32, dateActive: Int32, ip: String, region: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .webAuthorization(let hash, let botId, let domain, let browser, let platform, let dateCreated, let dateActive, let ip, let region): + if boxed { + buffer.appendInt32(-892779534) + } + serializeInt64(hash, buffer: buffer, boxed: false) + serializeInt32(botId, buffer: buffer, boxed: false) + serializeString(domain, buffer: buffer, boxed: false) + serializeString(browser, buffer: buffer, boxed: false) + serializeString(platform, buffer: buffer, boxed: false) + serializeInt32(dateCreated, buffer: buffer, boxed: false) + serializeInt32(dateActive, buffer: buffer, boxed: false) + serializeString(ip, buffer: buffer, boxed: false) + serializeString(region, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .webAuthorization(let hash, let botId, let domain, let browser, let platform, let dateCreated, let dateActive, let ip, let region): + return ("webAuthorization", [("hash", hash), ("botId", botId), ("domain", domain), ("browser", browser), ("platform", platform), ("dateCreated", dateCreated), ("dateActive", dateActive), ("ip", ip), ("region", region)]) + } + } + + static func parse_webAuthorization(_ reader: BufferReader) -> WebAuthorization? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: String? + _8 = parseString(reader) + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.WebAuthorization.webAuthorization(hash: _1!, botId: _2!, domain: _3!, browser: _4!, platform: _5!, dateCreated: _6!, dateActive: _7!, ip: _8!, region: _9!) + } + else { + return nil + } + } + + } + enum ImportedContact: TypeConstructorDescription { + case importedContact(userId: Int32, clientId: Int64) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .importedContact(let userId, let clientId): + if boxed { + buffer.appendInt32(-805141448) + } + serializeInt32(userId, buffer: buffer, boxed: false) + serializeInt64(clientId, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .importedContact(let userId, let clientId): + return ("importedContact", [("userId", userId), ("clientId", clientId)]) + } + } + + static func parse_importedContact(_ reader: BufferReader) -> ImportedContact? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ImportedContact.importedContact(userId: _1!, clientId: _2!) + } + else { + return nil + } + } + + } +} diff --git a/submodules/TelegramCore/TelegramCore/Api2.swift b/submodules/TelegramCore/TelegramCore/Api2.swift new file mode 100644 index 0000000000..59661bace0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Api2.swift @@ -0,0 +1,2424 @@ +extension Api { +struct channels { + enum ChannelParticipants: TypeConstructorDescription { + case channelParticipants(count: Int32, participants: [Api.ChannelParticipant], users: [Api.User]) + case channelParticipantsNotModified + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelParticipants(let count, let participants, let users): + if boxed { + buffer.appendInt32(-177282392) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(participants.count)) + for item in participants { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .channelParticipantsNotModified: + if boxed { + buffer.appendInt32(-266911767) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelParticipants(let count, let participants, let users): + return ("channelParticipants", [("count", count), ("participants", participants), ("users", users)]) + case .channelParticipantsNotModified: + return ("channelParticipantsNotModified", []) + } + } + + static func parse_channelParticipants(_ reader: BufferReader) -> ChannelParticipants? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.ChannelParticipant]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChannelParticipant.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.channels.ChannelParticipants.channelParticipants(count: _1!, participants: _2!, users: _3!) + } + else { + return nil + } + } + static func parse_channelParticipantsNotModified(_ reader: BufferReader) -> ChannelParticipants? { + return Api.channels.ChannelParticipants.channelParticipantsNotModified + } + + } + enum ChannelParticipant: TypeConstructorDescription { + case channelParticipant(participant: Api.ChannelParticipant, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelParticipant(let participant, let users): + if boxed { + buffer.appendInt32(-791039645) + } + participant.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelParticipant(let participant, let users): + return ("channelParticipant", [("participant", participant), ("users", users)]) + } + } + + static func parse_channelParticipant(_ reader: BufferReader) -> ChannelParticipant? { + var _1: Api.ChannelParticipant? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.channels.ChannelParticipant.channelParticipant(participant: _1!, users: _2!) + } + else { + return nil + } + } + + } + enum AdminLogResults: TypeConstructorDescription { + case adminLogResults(events: [Api.ChannelAdminLogEvent], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .adminLogResults(let events, let chats, let users): + if boxed { + buffer.appendInt32(-309659827) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(events.count)) + for item in events { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .adminLogResults(let events, let chats, let users): + return ("adminLogResults", [("events", events), ("chats", chats), ("users", users)]) + } + } + + static func parse_adminLogResults(_ reader: BufferReader) -> AdminLogResults? { + var _1: [Api.ChannelAdminLogEvent]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChannelAdminLogEvent.self) + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.channels.AdminLogResults.adminLogResults(events: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct payments { + enum ValidatedRequestedInfo: TypeConstructorDescription { + case validatedRequestedInfo(flags: Int32, id: String?, shippingOptions: [Api.ShippingOption]?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .validatedRequestedInfo(let flags, let id, let shippingOptions): + if boxed { + buffer.appendInt32(-784000893) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(id!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(shippingOptions!.count)) + for item in shippingOptions! { + item.serialize(buffer, true) + }} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .validatedRequestedInfo(let flags, let id, let shippingOptions): + return ("validatedRequestedInfo", [("flags", flags), ("id", id), ("shippingOptions", shippingOptions)]) + } + } + + static func parse_validatedRequestedInfo(_ reader: BufferReader) -> ValidatedRequestedInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: [Api.ShippingOption]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ShippingOption.self) + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.payments.ValidatedRequestedInfo.validatedRequestedInfo(flags: _1!, id: _2, shippingOptions: _3) + } + else { + return nil + } + } + + } + enum PaymentResult: TypeConstructorDescription { + case paymentResult(updates: Api.Updates) + case paymentVerficationNeeded(url: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentResult(let updates): + if boxed { + buffer.appendInt32(1314881805) + } + updates.serialize(buffer, true) + break + case .paymentVerficationNeeded(let url): + if boxed { + buffer.appendInt32(1800845601) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentResult(let updates): + return ("paymentResult", [("updates", updates)]) + case .paymentVerficationNeeded(let url): + return ("paymentVerficationNeeded", [("url", url)]) + } + } + + static func parse_paymentResult(_ reader: BufferReader) -> PaymentResult? { + var _1: Api.Updates? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Updates + } + let _c1 = _1 != nil + if _c1 { + return Api.payments.PaymentResult.paymentResult(updates: _1!) + } + else { + return nil + } + } + static func parse_paymentVerficationNeeded(_ reader: BufferReader) -> PaymentResult? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.payments.PaymentResult.paymentVerficationNeeded(url: _1!) + } + else { + return nil + } + } + + } + enum PaymentForm: TypeConstructorDescription { + case paymentForm(flags: Int32, botId: Int32, invoice: Api.Invoice, providerId: Int32, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: Api.PaymentSavedCredentials?, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentForm(let flags, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users): + if boxed { + buffer.appendInt32(1062645411) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(botId, buffer: buffer, boxed: false) + invoice.serialize(buffer, true) + serializeInt32(providerId, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {serializeString(nativeProvider!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {nativeParams!.serialize(buffer, true)} + if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {savedCredentials!.serialize(buffer, true)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentForm(let flags, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users): + return ("paymentForm", [("flags", flags), ("botId", botId), ("invoice", invoice), ("providerId", providerId), ("url", url), ("nativeProvider", nativeProvider), ("nativeParams", nativeParams), ("savedInfo", savedInfo), ("savedCredentials", savedCredentials), ("users", users)]) + } + } + + static func parse_paymentForm(_ reader: BufferReader) -> PaymentForm? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.Invoice? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Invoice + } + var _4: Int32? + _4 = reader.readInt32() + var _5: String? + _5 = parseString(reader) + var _6: String? + if Int(_1!) & Int(1 << 4) != 0 {_6 = parseString(reader) } + var _7: Api.DataJSON? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.DataJSON + } } + var _8: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + var _9: Api.PaymentSavedCredentials? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.PaymentSavedCredentials + } } + var _10: [Api.User]? + if let _ = reader.readInt32() { + _10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.payments.PaymentForm.paymentForm(flags: _1!, botId: _2!, invoice: _3!, providerId: _4!, url: _5!, nativeProvider: _6, nativeParams: _7, savedInfo: _8, savedCredentials: _9, users: _10!) + } + else { + return nil + } + } + + } + enum PaymentReceipt: TypeConstructorDescription { + case paymentReceipt(flags: Int32, date: Int32, botId: Int32, invoice: Api.Invoice, providerId: Int32, info: Api.PaymentRequestedInfo?, shipping: Api.ShippingOption?, currency: String, totalAmount: Int64, credentialsTitle: String, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .paymentReceipt(let flags, let date, let botId, let invoice, let providerId, let info, let shipping, let currency, let totalAmount, let credentialsTitle, let users): + if boxed { + buffer.appendInt32(1342771681) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(botId, buffer: buffer, boxed: false) + invoice.serialize(buffer, true) + serializeInt32(providerId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {info!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {shipping!.serialize(buffer, true)} + serializeString(currency, buffer: buffer, boxed: false) + serializeInt64(totalAmount, buffer: buffer, boxed: false) + serializeString(credentialsTitle, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .paymentReceipt(let flags, let date, let botId, let invoice, let providerId, let info, let shipping, let currency, let totalAmount, let credentialsTitle, let users): + return ("paymentReceipt", [("flags", flags), ("date", date), ("botId", botId), ("invoice", invoice), ("providerId", providerId), ("info", info), ("shipping", shipping), ("currency", currency), ("totalAmount", totalAmount), ("credentialsTitle", credentialsTitle), ("users", users)]) + } + } + + static func parse_paymentReceipt(_ reader: BufferReader) -> PaymentReceipt? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Api.Invoice? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Invoice + } + var _5: Int32? + _5 = reader.readInt32() + var _6: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + var _7: Api.ShippingOption? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.ShippingOption + } } + var _8: String? + _8 = parseString(reader) + var _9: Int64? + _9 = reader.readInt64() + var _10: String? + _10 = parseString(reader) + var _11: [Api.User]? + if let _ = reader.readInt32() { + _11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return Api.payments.PaymentReceipt.paymentReceipt(flags: _1!, date: _2!, botId: _3!, invoice: _4!, providerId: _5!, info: _6, shipping: _7, currency: _8!, totalAmount: _9!, credentialsTitle: _10!, users: _11!) + } + else { + return nil + } + } + + } + enum SavedInfo: TypeConstructorDescription { + case savedInfo(flags: Int32, savedInfo: Api.PaymentRequestedInfo?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .savedInfo(let flags, let savedInfo): + if boxed { + buffer.appendInt32(-74456004) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .savedInfo(let flags, let savedInfo): + return ("savedInfo", [("flags", flags), ("savedInfo", savedInfo)]) + } + } + + static func parse_savedInfo(_ reader: BufferReader) -> SavedInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + if _c1 && _c2 { + return Api.payments.SavedInfo.savedInfo(flags: _1!, savedInfo: _2) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct auth { + enum Authorization: TypeConstructorDescription { + case authorization(flags: Int32, tmpSessions: Int32?, user: Api.User) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .authorization(let flags, let tmpSessions, let user): + if boxed { + buffer.appendInt32(-855308010) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(tmpSessions!, buffer: buffer, boxed: false)} + user.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .authorization(let flags, let tmpSessions, let user): + return ("authorization", [("flags", flags), ("tmpSessions", tmpSessions), ("user", user)]) + } + } + + static func parse_authorization(_ reader: BufferReader) -> Authorization? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Api.User? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.User + } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.auth.Authorization.authorization(flags: _1!, tmpSessions: _2, user: _3!) + } + else { + return nil + } + } + + } + enum PasswordRecovery: TypeConstructorDescription { + case passwordRecovery(emailPattern: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .passwordRecovery(let emailPattern): + if boxed { + buffer.appendInt32(326715557) + } + serializeString(emailPattern, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .passwordRecovery(let emailPattern): + return ("passwordRecovery", [("emailPattern", emailPattern)]) + } + } + + static func parse_passwordRecovery(_ reader: BufferReader) -> PasswordRecovery? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.auth.PasswordRecovery.passwordRecovery(emailPattern: _1!) + } + else { + return nil + } + } + + } + enum ExportedAuthorization: TypeConstructorDescription { + case exportedAuthorization(id: Int32, bytes: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .exportedAuthorization(let id, let bytes): + if boxed { + buffer.appendInt32(-543777747) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .exportedAuthorization(let id, let bytes): + return ("exportedAuthorization", [("id", id), ("bytes", bytes)]) + } + } + + static func parse_exportedAuthorization(_ reader: BufferReader) -> ExportedAuthorization? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.auth.ExportedAuthorization.exportedAuthorization(id: _1!, bytes: _2!) + } + else { + return nil + } + } + + } + enum CheckedPhone: TypeConstructorDescription { + case checkedPhone(phoneRegistered: Api.Bool) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .checkedPhone(let phoneRegistered): + if boxed { + buffer.appendInt32(-2128698738) + } + phoneRegistered.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .checkedPhone(let phoneRegistered): + return ("checkedPhone", [("phoneRegistered", phoneRegistered)]) + } + } + + static func parse_checkedPhone(_ reader: BufferReader) -> CheckedPhone? { + var _1: Api.Bool? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Bool + } + let _c1 = _1 != nil + if _c1 { + return Api.auth.CheckedPhone.checkedPhone(phoneRegistered: _1!) + } + else { + return nil + } + } + + } + enum SentCode: TypeConstructorDescription { + case sentCode(flags: Int32, type: Api.auth.SentCodeType, phoneCodeHash: String, nextType: Api.auth.CodeType?, timeout: Int32?, termsOfService: Api.help.TermsOfService?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sentCode(let flags, let type, let phoneCodeHash, let nextType, let timeout, let termsOfService): + if boxed { + buffer.appendInt32(955951967) + } + serializeInt32(flags, buffer: buffer, boxed: false) + type.serialize(buffer, true) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {nextType!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {termsOfService!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sentCode(let flags, let type, let phoneCodeHash, let nextType, let timeout, let termsOfService): + return ("sentCode", [("flags", flags), ("type", type), ("phoneCodeHash", phoneCodeHash), ("nextType", nextType), ("timeout", timeout), ("termsOfService", termsOfService)]) + } + } + + static func parse_sentCode(_ reader: BufferReader) -> SentCode? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.auth.SentCodeType? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.auth.SentCodeType + } + var _3: String? + _3 = parseString(reader) + var _4: Api.auth.CodeType? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.auth.CodeType + } } + var _5: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_5 = reader.readInt32() } + var _6: Api.help.TermsOfService? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.help.TermsOfService + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.auth.SentCode.sentCode(flags: _1!, type: _2!, phoneCodeHash: _3!, nextType: _4, timeout: _5, termsOfService: _6) + } + else { + return nil + } + } + + } + enum CodeType: TypeConstructorDescription { + case codeTypeSms + case codeTypeCall + case codeTypeFlashCall + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .codeTypeSms: + if boxed { + buffer.appendInt32(1923290508) + } + + break + case .codeTypeCall: + if boxed { + buffer.appendInt32(1948046307) + } + + break + case .codeTypeFlashCall: + if boxed { + buffer.appendInt32(577556219) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .codeTypeSms: + return ("codeTypeSms", []) + case .codeTypeCall: + return ("codeTypeCall", []) + case .codeTypeFlashCall: + return ("codeTypeFlashCall", []) + } + } + + static func parse_codeTypeSms(_ reader: BufferReader) -> CodeType? { + return Api.auth.CodeType.codeTypeSms + } + static func parse_codeTypeCall(_ reader: BufferReader) -> CodeType? { + return Api.auth.CodeType.codeTypeCall + } + static func parse_codeTypeFlashCall(_ reader: BufferReader) -> CodeType? { + return Api.auth.CodeType.codeTypeFlashCall + } + + } + enum SentCodeType: TypeConstructorDescription { + case sentCodeTypeApp(length: Int32) + case sentCodeTypeSms(length: Int32) + case sentCodeTypeCall(length: Int32) + case sentCodeTypeFlashCall(pattern: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sentCodeTypeApp(let length): + if boxed { + buffer.appendInt32(1035688326) + } + serializeInt32(length, buffer: buffer, boxed: false) + break + case .sentCodeTypeSms(let length): + if boxed { + buffer.appendInt32(-1073693790) + } + serializeInt32(length, buffer: buffer, boxed: false) + break + case .sentCodeTypeCall(let length): + if boxed { + buffer.appendInt32(1398007207) + } + serializeInt32(length, buffer: buffer, boxed: false) + break + case .sentCodeTypeFlashCall(let pattern): + if boxed { + buffer.appendInt32(-1425815847) + } + serializeString(pattern, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sentCodeTypeApp(let length): + return ("sentCodeTypeApp", [("length", length)]) + case .sentCodeTypeSms(let length): + return ("sentCodeTypeSms", [("length", length)]) + case .sentCodeTypeCall(let length): + return ("sentCodeTypeCall", [("length", length)]) + case .sentCodeTypeFlashCall(let pattern): + return ("sentCodeTypeFlashCall", [("pattern", pattern)]) + } + } + + static func parse_sentCodeTypeApp(_ reader: BufferReader) -> SentCodeType? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.auth.SentCodeType.sentCodeTypeApp(length: _1!) + } + else { + return nil + } + } + static func parse_sentCodeTypeSms(_ reader: BufferReader) -> SentCodeType? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.auth.SentCodeType.sentCodeTypeSms(length: _1!) + } + else { + return nil + } + } + static func parse_sentCodeTypeCall(_ reader: BufferReader) -> SentCodeType? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.auth.SentCodeType.sentCodeTypeCall(length: _1!) + } + else { + return nil + } + } + static func parse_sentCodeTypeFlashCall(_ reader: BufferReader) -> SentCodeType? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.auth.SentCodeType.sentCodeTypeFlashCall(pattern: _1!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct contacts { + enum Blocked: TypeConstructorDescription { + case blocked(blocked: [Api.ContactBlocked], users: [Api.User]) + case blockedSlice(count: Int32, blocked: [Api.ContactBlocked], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .blocked(let blocked, let users): + if boxed { + buffer.appendInt32(471043349) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocked.count)) + for item in blocked { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .blockedSlice(let count, let blocked, let users): + if boxed { + buffer.appendInt32(-1878523231) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocked.count)) + for item in blocked { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .blocked(let blocked, let users): + return ("blocked", [("blocked", blocked), ("users", users)]) + case .blockedSlice(let count, let blocked, let users): + return ("blockedSlice", [("count", count), ("blocked", blocked), ("users", users)]) + } + } + + static func parse_blocked(_ reader: BufferReader) -> Blocked? { + var _1: [Api.ContactBlocked]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ContactBlocked.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.contacts.Blocked.blocked(blocked: _1!, users: _2!) + } + else { + return nil + } + } + static func parse_blockedSlice(_ reader: BufferReader) -> Blocked? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.ContactBlocked]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ContactBlocked.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.contacts.Blocked.blockedSlice(count: _1!, blocked: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum Contacts: TypeConstructorDescription { + case contactsNotModified + case contacts(contacts: [Api.Contact], savedCount: Int32, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .contactsNotModified: + if boxed { + buffer.appendInt32(-1219778094) + } + + break + case .contacts(let contacts, let savedCount, let users): + if boxed { + buffer.appendInt32(-353862078) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(contacts.count)) + for item in contacts { + item.serialize(buffer, true) + } + serializeInt32(savedCount, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .contactsNotModified: + return ("contactsNotModified", []) + case .contacts(let contacts, let savedCount, let users): + return ("contacts", [("contacts", contacts), ("savedCount", savedCount), ("users", users)]) + } + } + + static func parse_contactsNotModified(_ reader: BufferReader) -> Contacts? { + return Api.contacts.Contacts.contactsNotModified + } + static func parse_contacts(_ reader: BufferReader) -> Contacts? { + var _1: [Api.Contact]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Contact.self) + } + var _2: Int32? + _2 = reader.readInt32() + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.contacts.Contacts.contacts(contacts: _1!, savedCount: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum ResolvedPeer: TypeConstructorDescription { + case resolvedPeer(peer: Api.Peer, chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .resolvedPeer(let peer, let chats, let users): + if boxed { + buffer.appendInt32(2131196633) + } + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .resolvedPeer(let peer, let chats, let users): + return ("resolvedPeer", [("peer", peer), ("chats", chats), ("users", users)]) + } + } + + static func parse_resolvedPeer(_ reader: BufferReader) -> ResolvedPeer? { + var _1: Api.Peer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.contacts.ResolvedPeer.resolvedPeer(peer: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum ImportedContacts: TypeConstructorDescription { + case importedContacts(imported: [Api.ImportedContact], popularInvites: [Api.PopularContact], retryContacts: [Int64], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .importedContacts(let imported, let popularInvites, let retryContacts, let users): + if boxed { + buffer.appendInt32(2010127419) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(imported.count)) + for item in imported { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(popularInvites.count)) + for item in popularInvites { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(retryContacts.count)) + for item in retryContacts { + serializeInt64(item, buffer: buffer, boxed: false) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .importedContacts(let imported, let popularInvites, let retryContacts, let users): + return ("importedContacts", [("imported", imported), ("popularInvites", popularInvites), ("retryContacts", retryContacts), ("users", users)]) + } + } + + static func parse_importedContacts(_ reader: BufferReader) -> ImportedContacts? { + var _1: [Api.ImportedContact]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ImportedContact.self) + } + var _2: [Api.PopularContact]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PopularContact.self) + } + var _3: [Int64]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.contacts.ImportedContacts.importedContacts(imported: _1!, popularInvites: _2!, retryContacts: _3!, users: _4!) + } + else { + return nil + } + } + + } + enum Found: TypeConstructorDescription { + case found(myResults: [Api.Peer], results: [Api.Peer], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .found(let myResults, let results, let chats, let users): + if boxed { + buffer.appendInt32(-1290580579) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(myResults.count)) + for item in myResults { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(results.count)) + for item in results { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .found(let myResults, let results, let chats, let users): + return ("found", [("myResults", myResults), ("results", results), ("chats", chats), ("users", users)]) + } + } + + static func parse_found(_ reader: BufferReader) -> Found? { + var _1: [Api.Peer]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self) + } + var _2: [Api.Peer]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.contacts.Found.found(myResults: _1!, results: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + + } + enum TopPeers: TypeConstructorDescription { + case topPeersNotModified + case topPeers(categories: [Api.TopPeerCategoryPeers], chats: [Api.Chat], users: [Api.User]) + case topPeersDisabled + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .topPeersNotModified: + if boxed { + buffer.appendInt32(-567906571) + } + + break + case .topPeers(let categories, let chats, let users): + if boxed { + buffer.appendInt32(1891070632) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(categories.count)) + for item in categories { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .topPeersDisabled: + if boxed { + buffer.appendInt32(-1255369827) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .topPeersNotModified: + return ("topPeersNotModified", []) + case .topPeers(let categories, let chats, let users): + return ("topPeers", [("categories", categories), ("chats", chats), ("users", users)]) + case .topPeersDisabled: + return ("topPeersDisabled", []) + } + } + + static func parse_topPeersNotModified(_ reader: BufferReader) -> TopPeers? { + return Api.contacts.TopPeers.topPeersNotModified + } + static func parse_topPeers(_ reader: BufferReader) -> TopPeers? { + var _1: [Api.TopPeerCategoryPeers]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.TopPeerCategoryPeers.self) + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.contacts.TopPeers.topPeers(categories: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + static func parse_topPeersDisabled(_ reader: BufferReader) -> TopPeers? { + return Api.contacts.TopPeers.topPeersDisabled + } + + } +} +} +extension Api { +struct help { + enum AppUpdate: TypeConstructorDescription { + case appUpdate(id: Int32, critical: Api.Bool, url: String, text: String) + case noAppUpdate + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .appUpdate(let id, let critical, let url, let text): + if boxed { + buffer.appendInt32(-1987579119) + } + serializeInt32(id, buffer: buffer, boxed: false) + critical.serialize(buffer, true) + serializeString(url, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .noAppUpdate: + if boxed { + buffer.appendInt32(-1000708810) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .appUpdate(let id, let critical, let url, let text): + return ("appUpdate", [("id", id), ("critical", critical), ("url", url), ("text", text)]) + case .noAppUpdate: + return ("noAppUpdate", []) + } + } + + static func parse_appUpdate(_ reader: BufferReader) -> AppUpdate? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Bool? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Bool + } + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.help.AppUpdate.appUpdate(id: _1!, critical: _2!, url: _3!, text: _4!) + } + else { + return nil + } + } + static func parse_noAppUpdate(_ reader: BufferReader) -> AppUpdate? { + return Api.help.AppUpdate.noAppUpdate + } + + } + enum PassportConfig: TypeConstructorDescription { + case passportConfigNotModified + case passportConfig(hash: Int32, countriesLangs: Api.DataJSON) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .passportConfigNotModified: + if boxed { + buffer.appendInt32(-1078332329) + } + + break + case .passportConfig(let hash, let countriesLangs): + if boxed { + buffer.appendInt32(-1600596305) + } + serializeInt32(hash, buffer: buffer, boxed: false) + countriesLangs.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .passportConfigNotModified: + return ("passportConfigNotModified", []) + case .passportConfig(let hash, let countriesLangs): + return ("passportConfig", [("hash", hash), ("countriesLangs", countriesLangs)]) + } + } + + static func parse_passportConfigNotModified(_ reader: BufferReader) -> PassportConfig? { + return Api.help.PassportConfig.passportConfigNotModified + } + static func parse_passportConfig(_ reader: BufferReader) -> PassportConfig? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.DataJSON? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.help.PassportConfig.passportConfig(hash: _1!, countriesLangs: _2!) + } + else { + return nil + } + } + + } + enum ProxyData: TypeConstructorDescription { + case proxyDataEmpty(expires: Int32) + case proxyDataPromo(expires: Int32, peer: Api.Peer, chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .proxyDataEmpty(let expires): + if boxed { + buffer.appendInt32(-526508104) + } + serializeInt32(expires, buffer: buffer, boxed: false) + break + case .proxyDataPromo(let expires, let peer, let chats, let users): + if boxed { + buffer.appendInt32(737668643) + } + serializeInt32(expires, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .proxyDataEmpty(let expires): + return ("proxyDataEmpty", [("expires", expires)]) + case .proxyDataPromo(let expires, let peer, let chats, let users): + return ("proxyDataPromo", [("expires", expires), ("peer", peer), ("chats", chats), ("users", users)]) + } + } + + static func parse_proxyDataEmpty(_ reader: BufferReader) -> ProxyData? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.help.ProxyData.proxyDataEmpty(expires: _1!) + } + else { + return nil + } + } + static func parse_proxyDataPromo(_ reader: BufferReader) -> ProxyData? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.Peer? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Peer + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.help.ProxyData.proxyDataPromo(expires: _1!, peer: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + + } + enum DeepLinkInfo: TypeConstructorDescription { + case deepLinkInfoEmpty + case deepLinkInfo(flags: Int32, message: String, entities: [Api.MessageEntity]?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .deepLinkInfoEmpty: + if boxed { + buffer.appendInt32(1722786150) + } + + break + case .deepLinkInfo(let flags, let message, let entities): + if boxed { + buffer.appendInt32(1783556146) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .deepLinkInfoEmpty: + return ("deepLinkInfoEmpty", []) + case .deepLinkInfo(let flags, let message, let entities): + return ("deepLinkInfo", [("flags", flags), ("message", message), ("entities", entities)]) + } + } + + static func parse_deepLinkInfoEmpty(_ reader: BufferReader) -> DeepLinkInfo? { + return Api.help.DeepLinkInfo.deepLinkInfoEmpty + } + static func parse_deepLinkInfo(_ reader: BufferReader) -> DeepLinkInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.help.DeepLinkInfo.deepLinkInfo(flags: _1!, message: _2!, entities: _3) + } + else { + return nil + } + } + + } + enum TermsOfService: TypeConstructorDescription { + case termsOfService(flags: Int32, id: Api.DataJSON, text: String, entities: [Api.MessageEntity], minAgeConfirm: Int32?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .termsOfService(let flags, let id, let text, let entities, let minAgeConfirm): + if boxed { + buffer.appendInt32(2013922064) + } + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + serializeString(text, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities.count)) + for item in entities { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(minAgeConfirm!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .termsOfService(let flags, let id, let text, let entities, let minAgeConfirm): + return ("termsOfService", [("flags", flags), ("id", id), ("text", text), ("entities", entities), ("minAgeConfirm", minAgeConfirm)]) + } + } + + static func parse_termsOfService(_ reader: BufferReader) -> TermsOfService? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.DataJSON? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + var _3: String? + _3 = parseString(reader) + var _4: [Api.MessageEntity]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } + var _5: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.help.TermsOfService.termsOfService(flags: _1!, id: _2!, text: _3!, entities: _4!, minAgeConfirm: _5) + } + else { + return nil + } + } + + } + enum RecentMeUrls: TypeConstructorDescription { + case recentMeUrls(urls: [Api.RecentMeUrl], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .recentMeUrls(let urls, let chats, let users): + if boxed { + buffer.appendInt32(235081943) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(urls.count)) + for item in urls { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .recentMeUrls(let urls, let chats, let users): + return ("recentMeUrls", [("urls", urls), ("chats", chats), ("users", users)]) + } + } + + static func parse_recentMeUrls(_ reader: BufferReader) -> RecentMeUrls? { + var _1: [Api.RecentMeUrl]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RecentMeUrl.self) + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.help.RecentMeUrls.recentMeUrls(urls: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum Support: TypeConstructorDescription { + case support(phoneNumber: String, user: Api.User) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .support(let phoneNumber, let user): + if boxed { + buffer.appendInt32(398898678) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + user.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .support(let phoneNumber, let user): + return ("support", [("phoneNumber", phoneNumber), ("user", user)]) + } + } + + static func parse_support(_ reader: BufferReader) -> Support? { + var _1: String? + _1 = parseString(reader) + var _2: Api.User? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.User + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.help.Support.support(phoneNumber: _1!, user: _2!) + } + else { + return nil + } + } + + } + enum InviteText: TypeConstructorDescription { + case inviteText(message: String) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inviteText(let message): + if boxed { + buffer.appendInt32(415997816) + } + serializeString(message, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inviteText(let message): + return ("inviteText", [("message", message)]) + } + } + + static func parse_inviteText(_ reader: BufferReader) -> InviteText? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.help.InviteText.inviteText(message: _1!) + } + else { + return nil + } + } + + } + enum TermsOfServiceUpdate: TypeConstructorDescription { + case termsOfServiceUpdateEmpty(expires: Int32) + case termsOfServiceUpdate(expires: Int32, termsOfService: Api.help.TermsOfService) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .termsOfServiceUpdateEmpty(let expires): + if boxed { + buffer.appendInt32(-483352705) + } + serializeInt32(expires, buffer: buffer, boxed: false) + break + case .termsOfServiceUpdate(let expires, let termsOfService): + if boxed { + buffer.appendInt32(686618977) + } + serializeInt32(expires, buffer: buffer, boxed: false) + termsOfService.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .termsOfServiceUpdateEmpty(let expires): + return ("termsOfServiceUpdateEmpty", [("expires", expires)]) + case .termsOfServiceUpdate(let expires, let termsOfService): + return ("termsOfServiceUpdate", [("expires", expires), ("termsOfService", termsOfService)]) + } + } + + static func parse_termsOfServiceUpdateEmpty(_ reader: BufferReader) -> TermsOfServiceUpdate? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.help.TermsOfServiceUpdate.termsOfServiceUpdateEmpty(expires: _1!) + } + else { + return nil + } + } + static func parse_termsOfServiceUpdate(_ reader: BufferReader) -> TermsOfServiceUpdate? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.help.TermsOfService? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.help.TermsOfService + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.help.TermsOfServiceUpdate.termsOfServiceUpdate(expires: _1!, termsOfService: _2!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct updates { + enum Difference: TypeConstructorDescription { + case differenceEmpty(date: Int32, seq: Int32) + case difference(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], state: Api.updates.State) + case differenceSlice(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], intermediateState: Api.updates.State) + case differenceTooLong(pts: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .differenceEmpty(let date, let seq): + if boxed { + buffer.appendInt32(1567990072) + } + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + break + case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state): + if boxed { + buffer.appendInt32(16030880) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newMessages.count)) + for item in newMessages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newEncryptedMessages.count)) + for item in newEncryptedMessages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(otherUpdates.count)) + for item in otherUpdates { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + state.serialize(buffer, true) + break + case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState): + if boxed { + buffer.appendInt32(-1459938943) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newMessages.count)) + for item in newMessages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newEncryptedMessages.count)) + for item in newEncryptedMessages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(otherUpdates.count)) + for item in otherUpdates { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + intermediateState.serialize(buffer, true) + break + case .differenceTooLong(let pts): + if boxed { + buffer.appendInt32(1258196845) + } + serializeInt32(pts, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .differenceEmpty(let date, let seq): + return ("differenceEmpty", [("date", date), ("seq", seq)]) + case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state): + return ("difference", [("newMessages", newMessages), ("newEncryptedMessages", newEncryptedMessages), ("otherUpdates", otherUpdates), ("chats", chats), ("users", users), ("state", state)]) + case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState): + return ("differenceSlice", [("newMessages", newMessages), ("newEncryptedMessages", newEncryptedMessages), ("otherUpdates", otherUpdates), ("chats", chats), ("users", users), ("intermediateState", intermediateState)]) + case .differenceTooLong(let pts): + return ("differenceTooLong", [("pts", pts)]) + } + } + + static func parse_differenceEmpty(_ reader: BufferReader) -> Difference? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.updates.Difference.differenceEmpty(date: _1!, seq: _2!) + } + else { + return nil + } + } + static func parse_difference(_ reader: BufferReader) -> Difference? { + var _1: [Api.Message]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _2: [Api.EncryptedMessage]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self) + } + var _3: [Api.Update]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self) + } + var _4: [Api.Chat]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _6: Api.updates.State? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.updates.State + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.updates.Difference.difference(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, state: _6!) + } + else { + return nil + } + } + static func parse_differenceSlice(_ reader: BufferReader) -> Difference? { + var _1: [Api.Message]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _2: [Api.EncryptedMessage]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self) + } + var _3: [Api.Update]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self) + } + var _4: [Api.Chat]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _6: Api.updates.State? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.updates.State + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.updates.Difference.differenceSlice(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, intermediateState: _6!) + } + else { + return nil + } + } + static func parse_differenceTooLong(_ reader: BufferReader) -> Difference? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.updates.Difference.differenceTooLong(pts: _1!) + } + else { + return nil + } + } + + } + enum State: TypeConstructorDescription { + case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + if boxed { + buffer.appendInt32(-1519637954) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(qts, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + serializeInt32(unreadCount, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + return ("state", [("pts", pts), ("qts", qts), ("date", date), ("seq", seq), ("unreadCount", unreadCount)]) + } + } + + static func parse_state(_ reader: BufferReader) -> State? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.updates.State.state(pts: _1!, qts: _2!, date: _3!, seq: _4!, unreadCount: _5!) + } + else { + return nil + } + } + + } + enum ChannelDifference: TypeConstructorDescription { + case channelDifferenceEmpty(flags: Int32, pts: Int32, timeout: Int32?) + case channelDifference(flags: Int32, pts: Int32, timeout: Int32?, newMessages: [Api.Message], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User]) + case channelDifferenceTooLong(flags: Int32, timeout: Int32?, dialog: Api.Dialog, messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .channelDifferenceEmpty(let flags, let pts, let timeout): + if boxed { + buffer.appendInt32(1041346555) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)} + break + case .channelDifference(let flags, let pts, let timeout, let newMessages, let otherUpdates, let chats, let users): + if boxed { + buffer.appendInt32(543450958) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newMessages.count)) + for item in newMessages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(otherUpdates.count)) + for item in otherUpdates { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .channelDifferenceTooLong(let flags, let timeout, let dialog, let messages, let chats, let users): + if boxed { + buffer.appendInt32(-1531132162) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)} + dialog.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .channelDifferenceEmpty(let flags, let pts, let timeout): + return ("channelDifferenceEmpty", [("flags", flags), ("pts", pts), ("timeout", timeout)]) + case .channelDifference(let flags, let pts, let timeout, let newMessages, let otherUpdates, let chats, let users): + return ("channelDifference", [("flags", flags), ("pts", pts), ("timeout", timeout), ("newMessages", newMessages), ("otherUpdates", otherUpdates), ("chats", chats), ("users", users)]) + case .channelDifferenceTooLong(let flags, let timeout, let dialog, let messages, let chats, let users): + return ("channelDifferenceTooLong", [("flags", flags), ("timeout", timeout), ("dialog", dialog), ("messages", messages), ("chats", chats), ("users", users)]) + } + } + + static func parse_channelDifferenceEmpty(_ reader: BufferReader) -> ChannelDifference? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.updates.ChannelDifference.channelDifferenceEmpty(flags: _1!, pts: _2!, timeout: _3) + } + else { + return nil + } + } + static func parse_channelDifference(_ reader: BufferReader) -> ChannelDifference? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() } + var _4: [Api.Message]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _5: [Api.Update]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self) + } + var _6: [Api.Chat]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _7: [Api.User]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.updates.ChannelDifference.channelDifference(flags: _1!, pts: _2!, timeout: _3, newMessages: _4!, otherUpdates: _5!, chats: _6!, users: _7!) + } + else { + return nil + } + } + static func parse_channelDifferenceTooLong(_ reader: BufferReader) -> ChannelDifference? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() } + var _3: Api.Dialog? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Dialog + } + var _4: [Api.Message]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _5: [Api.Chat]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _6: [Api.User]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.updates.ChannelDifference.channelDifferenceTooLong(flags: _1!, timeout: _2, dialog: _3!, messages: _4!, chats: _5!, users: _6!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct upload { + enum WebFile: TypeConstructorDescription { + case webFile(size: Int32, mimeType: String, fileType: Api.storage.FileType, mtime: Int32, bytes: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .webFile(let size, let mimeType, let fileType, let mtime, let bytes): + if boxed { + buffer.appendInt32(568808380) + } + serializeInt32(size, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + fileType.serialize(buffer, true) + serializeInt32(mtime, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .webFile(let size, let mimeType, let fileType, let mtime, let bytes): + return ("webFile", [("size", size), ("mimeType", mimeType), ("fileType", fileType), ("mtime", mtime), ("bytes", bytes)]) + } + } + + static func parse_webFile(_ reader: BufferReader) -> WebFile? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Api.storage.FileType? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.storage.FileType + } + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.upload.WebFile.webFile(size: _1!, mimeType: _2!, fileType: _3!, mtime: _4!, bytes: _5!) + } + else { + return nil + } + } + + } + enum File: TypeConstructorDescription { + case file(type: Api.storage.FileType, mtime: Int32, bytes: Buffer) + case fileCdnRedirect(dcId: Int32, fileToken: Buffer, encryptionKey: Buffer, encryptionIv: Buffer, fileHashes: [Api.FileHash]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .file(let type, let mtime, let bytes): + if boxed { + buffer.appendInt32(157948117) + } + type.serialize(buffer, true) + serializeInt32(mtime, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + case .fileCdnRedirect(let dcId, let fileToken, let encryptionKey, let encryptionIv, let fileHashes): + if boxed { + buffer.appendInt32(-242427324) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeBytes(fileToken, buffer: buffer, boxed: false) + serializeBytes(encryptionKey, buffer: buffer, boxed: false) + serializeBytes(encryptionIv, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(fileHashes.count)) + for item in fileHashes { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .file(let type, let mtime, let bytes): + return ("file", [("type", type), ("mtime", mtime), ("bytes", bytes)]) + case .fileCdnRedirect(let dcId, let fileToken, let encryptionKey, let encryptionIv, let fileHashes): + return ("fileCdnRedirect", [("dcId", dcId), ("fileToken", fileToken), ("encryptionKey", encryptionKey), ("encryptionIv", encryptionIv), ("fileHashes", fileHashes)]) + } + } + + static func parse_file(_ reader: BufferReader) -> File? { + var _1: Api.storage.FileType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.storage.FileType + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.upload.File.file(type: _1!, mtime: _2!, bytes: _3!) + } + else { + return nil + } + } + static func parse_fileCdnRedirect(_ reader: BufferReader) -> File? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Buffer? + _4 = parseBytes(reader) + var _5: [Api.FileHash]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.FileHash.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.upload.File.fileCdnRedirect(dcId: _1!, fileToken: _2!, encryptionKey: _3!, encryptionIv: _4!, fileHashes: _5!) + } + else { + return nil + } + } + + } + enum CdnFile: TypeConstructorDescription { + case cdnFileReuploadNeeded(requestToken: Buffer) + case cdnFile(bytes: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .cdnFileReuploadNeeded(let requestToken): + if boxed { + buffer.appendInt32(-290921362) + } + serializeBytes(requestToken, buffer: buffer, boxed: false) + break + case .cdnFile(let bytes): + if boxed { + buffer.appendInt32(-1449145777) + } + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .cdnFileReuploadNeeded(let requestToken): + return ("cdnFileReuploadNeeded", [("requestToken", requestToken)]) + case .cdnFile(let bytes): + return ("cdnFile", [("bytes", bytes)]) + } + } + + static func parse_cdnFileReuploadNeeded(_ reader: BufferReader) -> CdnFile? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.upload.CdnFile.cdnFileReuploadNeeded(requestToken: _1!) + } + else { + return nil + } + } + static func parse_cdnFile(_ reader: BufferReader) -> CdnFile? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.upload.CdnFile.cdnFile(bytes: _1!) + } + else { + return nil + } + } + + } +} +} diff --git a/submodules/TelegramCore/TelegramCore/Api3.swift b/submodules/TelegramCore/TelegramCore/Api3.swift new file mode 100644 index 0000000000..efd1324bb8 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Api3.swift @@ -0,0 +1,5560 @@ +extension Api { +struct storage { + enum FileType: TypeConstructorDescription { + case fileUnknown + case filePartial + case fileJpeg + case fileGif + case filePng + case filePdf + case fileMp3 + case fileMov + case fileMp4 + case fileWebp + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileUnknown: + if boxed { + buffer.appendInt32(-1432995067) + } + + break + case .filePartial: + if boxed { + buffer.appendInt32(1086091090) + } + + break + case .fileJpeg: + if boxed { + buffer.appendInt32(8322574) + } + + break + case .fileGif: + if boxed { + buffer.appendInt32(-891180321) + } + + break + case .filePng: + if boxed { + buffer.appendInt32(172975040) + } + + break + case .filePdf: + if boxed { + buffer.appendInt32(-1373745011) + } + + break + case .fileMp3: + if boxed { + buffer.appendInt32(1384777335) + } + + break + case .fileMov: + if boxed { + buffer.appendInt32(1258941372) + } + + break + case .fileMp4: + if boxed { + buffer.appendInt32(-1278304028) + } + + break + case .fileWebp: + if boxed { + buffer.appendInt32(276907596) + } + + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .fileUnknown: + return ("fileUnknown", []) + case .filePartial: + return ("filePartial", []) + case .fileJpeg: + return ("fileJpeg", []) + case .fileGif: + return ("fileGif", []) + case .filePng: + return ("filePng", []) + case .filePdf: + return ("filePdf", []) + case .fileMp3: + return ("fileMp3", []) + case .fileMov: + return ("fileMov", []) + case .fileMp4: + return ("fileMp4", []) + case .fileWebp: + return ("fileWebp", []) + } + } + + static func parse_fileUnknown(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileUnknown + } + static func parse_filePartial(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePartial + } + static func parse_fileJpeg(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileJpeg + } + static func parse_fileGif(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileGif + } + static func parse_filePng(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePng + } + static func parse_filePdf(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePdf + } + static func parse_fileMp3(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMp3 + } + static func parse_fileMov(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMov + } + static func parse_fileMp4(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMp4 + } + static func parse_fileWebp(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileWebp + } + + } +} +} +extension Api { +struct account { + enum TmpPassword: TypeConstructorDescription { + case tmpPassword(tmpPassword: Buffer, validUntil: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .tmpPassword(let tmpPassword, let validUntil): + if boxed { + buffer.appendInt32(-614138572) + } + serializeBytes(tmpPassword, buffer: buffer, boxed: false) + serializeInt32(validUntil, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .tmpPassword(let tmpPassword, let validUntil): + return ("tmpPassword", [("tmpPassword", tmpPassword), ("validUntil", validUntil)]) + } + } + + static func parse_tmpPassword(_ reader: BufferReader) -> TmpPassword? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.TmpPassword.tmpPassword(tmpPassword: _1!, validUntil: _2!) + } + else { + return nil + } + } + + } + enum PasswordSettings: TypeConstructorDescription { + case passwordSettings(flags: Int32, email: String?, secureSettings: Api.SecureSecretSettings?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .passwordSettings(let flags, let email, let secureSettings): + if boxed { + buffer.appendInt32(-1705233435) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(email!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {secureSettings!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .passwordSettings(let flags, let email, let secureSettings): + return ("passwordSettings", [("flags", flags), ("email", email), ("secureSettings", secureSettings)]) + } + } + + static func parse_passwordSettings(_ reader: BufferReader) -> PasswordSettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: Api.SecureSecretSettings? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.SecureSecretSettings + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.account.PasswordSettings.passwordSettings(flags: _1!, email: _2, secureSettings: _3) + } + else { + return nil + } + } + + } + enum WallPapers: TypeConstructorDescription { + case wallPapersNotModified + case wallPapers(hash: Int32, wallpapers: [Api.WallPaper]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .wallPapersNotModified: + if boxed { + buffer.appendInt32(471437699) + } + + break + case .wallPapers(let hash, let wallpapers): + if boxed { + buffer.appendInt32(1881892265) + } + serializeInt32(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(wallpapers.count)) + for item in wallpapers { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .wallPapersNotModified: + return ("wallPapersNotModified", []) + case .wallPapers(let hash, let wallpapers): + return ("wallPapers", [("hash", hash), ("wallpapers", wallpapers)]) + } + } + + static func parse_wallPapersNotModified(_ reader: BufferReader) -> WallPapers? { + return Api.account.WallPapers.wallPapersNotModified + } + static func parse_wallPapers(_ reader: BufferReader) -> WallPapers? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.WallPaper]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.WallPaper.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.WallPapers.wallPapers(hash: _1!, wallpapers: _2!) + } + else { + return nil + } + } + + } + enum PasswordInputSettings: TypeConstructorDescription { + case passwordInputSettings(flags: Int32, newAlgo: Api.PasswordKdfAlgo?, newPasswordHash: Buffer?, hint: String?, email: String?, newSecureSettings: Api.SecureSecretSettings?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .passwordInputSettings(let flags, let newAlgo, let newPasswordHash, let hint, let email, let newSecureSettings): + if boxed { + buffer.appendInt32(-1036572727) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {newAlgo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(newPasswordHash!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 0) != 0 {serializeString(hint!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(email!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {newSecureSettings!.serialize(buffer, true)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .passwordInputSettings(let flags, let newAlgo, let newPasswordHash, let hint, let email, let newSecureSettings): + return ("passwordInputSettings", [("flags", flags), ("newAlgo", newAlgo), ("newPasswordHash", newPasswordHash), ("hint", hint), ("email", email), ("newSecureSettings", newSecureSettings)]) + } + } + + static func parse_passwordInputSettings(_ reader: BufferReader) -> PasswordInputSettings? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.PasswordKdfAlgo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo + } } + var _3: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseBytes(reader) } + var _4: String? + if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } + var _6: Api.SecureSecretSettings? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.SecureSecretSettings + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.account.PasswordInputSettings.passwordInputSettings(flags: _1!, newAlgo: _2, newPasswordHash: _3, hint: _4, email: _5, newSecureSettings: _6) + } + else { + return nil + } + } + + } + enum WebAuthorizations: TypeConstructorDescription { + case webAuthorizations(authorizations: [Api.WebAuthorization], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .webAuthorizations(let authorizations, let users): + if boxed { + buffer.appendInt32(-313079300) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(authorizations.count)) + for item in authorizations { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .webAuthorizations(let authorizations, let users): + return ("webAuthorizations", [("authorizations", authorizations), ("users", users)]) + } + } + + static func parse_webAuthorizations(_ reader: BufferReader) -> WebAuthorizations? { + var _1: [Api.WebAuthorization]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.WebAuthorization.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.WebAuthorizations.webAuthorizations(authorizations: _1!, users: _2!) + } + else { + return nil + } + } + + } + enum SentEmailCode: TypeConstructorDescription { + case sentEmailCode(emailPattern: String, length: Int32) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sentEmailCode(let emailPattern, let length): + if boxed { + buffer.appendInt32(-2128640689) + } + serializeString(emailPattern, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sentEmailCode(let emailPattern, let length): + return ("sentEmailCode", [("emailPattern", emailPattern), ("length", length)]) + } + } + + static func parse_sentEmailCode(_ reader: BufferReader) -> SentEmailCode? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.SentEmailCode.sentEmailCode(emailPattern: _1!, length: _2!) + } + else { + return nil + } + } + + } + enum Authorizations: TypeConstructorDescription { + case authorizations(authorizations: [Api.Authorization]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .authorizations(let authorizations): + if boxed { + buffer.appendInt32(307276766) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(authorizations.count)) + for item in authorizations { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .authorizations(let authorizations): + return ("authorizations", [("authorizations", authorizations)]) + } + } + + static func parse_authorizations(_ reader: BufferReader) -> Authorizations? { + var _1: [Api.Authorization]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Authorization.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.account.Authorizations.authorizations(authorizations: _1!) + } + else { + return nil + } + } + + } + enum AuthorizationForm: TypeConstructorDescription { + case authorizationForm(flags: Int32, requiredTypes: [Api.SecureRequiredType], values: [Api.SecureValue], errors: [Api.SecureValueError], users: [Api.User], privacyPolicyUrl: String?) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .authorizationForm(let flags, let requiredTypes, let values, let errors, let users, let privacyPolicyUrl): + if boxed { + buffer.appendInt32(-1389486888) + } + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(requiredTypes.count)) + for item in requiredTypes { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(values.count)) + for item in values { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(errors.count)) + for item in errors { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 0) != 0 {serializeString(privacyPolicyUrl!, buffer: buffer, boxed: false)} + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .authorizationForm(let flags, let requiredTypes, let values, let errors, let users, let privacyPolicyUrl): + return ("authorizationForm", [("flags", flags), ("requiredTypes", requiredTypes), ("values", values), ("errors", errors), ("users", users), ("privacyPolicyUrl", privacyPolicyUrl)]) + } + } + + static func parse_authorizationForm(_ reader: BufferReader) -> AuthorizationForm? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.SecureRequiredType]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureRequiredType.self) + } + var _3: [Api.SecureValue]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) + } + var _4: [Api.SecureValueError]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValueError.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _6: String? + if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.account.AuthorizationForm.authorizationForm(flags: _1!, requiredTypes: _2!, values: _3!, errors: _4!, users: _5!, privacyPolicyUrl: _6) + } + else { + return nil + } + } + + } + enum Password: TypeConstructorDescription { + case password(flags: Int32, currentAlgo: Api.PasswordKdfAlgo?, srpB: Buffer?, srpId: Int64?, hint: String?, emailUnconfirmedPattern: String?, newAlgo: Api.PasswordKdfAlgo, newSecureAlgo: Api.SecurePasswordKdfAlgo, secureRandom: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .password(let flags, let currentAlgo, let srpB, let srpId, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): + if boxed { + buffer.appendInt32(-1390001672) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {currentAlgo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(srpB!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt64(srpId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(hint!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {serializeString(emailUnconfirmedPattern!, buffer: buffer, boxed: false)} + newAlgo.serialize(buffer, true) + newSecureAlgo.serialize(buffer, true) + serializeBytes(secureRandom, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .password(let flags, let currentAlgo, let srpB, let srpId, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): + return ("password", [("flags", flags), ("currentAlgo", currentAlgo), ("srpB", srpB), ("srpId", srpId), ("hint", hint), ("emailUnconfirmedPattern", emailUnconfirmedPattern), ("newAlgo", newAlgo), ("newSecureAlgo", newSecureAlgo), ("secureRandom", secureRandom)]) + } + } + + static func parse_password(_ reader: BufferReader) -> Password? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.PasswordKdfAlgo? + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo + } } + var _3: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_3 = parseBytes(reader) } + var _4: Int64? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt64() } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 4) != 0 {_6 = parseString(reader) } + var _7: Api.PasswordKdfAlgo? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo + } + var _8: Api.SecurePasswordKdfAlgo? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.SecurePasswordKdfAlgo + } + var _9: Buffer? + _9 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.account.Password.password(flags: _1!, currentAlgo: _2, srpB: _3, srpId: _4, hint: _5, emailUnconfirmedPattern: _6, newAlgo: _7!, newSecureAlgo: _8!, secureRandom: _9!) + } + else { + return nil + } + } + + } + enum PrivacyRules: TypeConstructorDescription { + case privacyRules(rules: [Api.PrivacyRule], chats: [Api.Chat], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .privacyRules(let rules, let chats, let users): + if boxed { + buffer.appendInt32(1352683077) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rules.count)) + for item in rules { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .privacyRules(let rules, let chats, let users): + return ("privacyRules", [("rules", rules), ("chats", chats), ("users", users)]) + } + } + + static func parse_privacyRules(_ reader: BufferReader) -> PrivacyRules? { + var _1: [Api.PrivacyRule]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self) + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.account.PrivacyRules.privacyRules(rules: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } + enum AutoDownloadSettings: TypeConstructorDescription { + case autoDownloadSettings(low: Api.AutoDownloadSettings, medium: Api.AutoDownloadSettings, high: Api.AutoDownloadSettings) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .autoDownloadSettings(let low, let medium, let high): + if boxed { + buffer.appendInt32(1674235686) + } + low.serialize(buffer, true) + medium.serialize(buffer, true) + high.serialize(buffer, true) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .autoDownloadSettings(let low, let medium, let high): + return ("autoDownloadSettings", [("low", low), ("medium", medium), ("high", high)]) + } + } + + static func parse_autoDownloadSettings(_ reader: BufferReader) -> AutoDownloadSettings? { + var _1: Api.AutoDownloadSettings? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.AutoDownloadSettings + } + var _2: Api.AutoDownloadSettings? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.AutoDownloadSettings + } + var _3: Api.AutoDownloadSettings? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.AutoDownloadSettings + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.account.AutoDownloadSettings.autoDownloadSettings(low: _1!, medium: _2!, high: _3!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct photos { + enum Photo: TypeConstructorDescription { + case photo(photo: Api.Photo, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photo(let photo, let users): + if boxed { + buffer.appendInt32(539045032) + } + photo.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .photo(let photo, let users): + return ("photo", [("photo", photo), ("users", users)]) + } + } + + static func parse_photo(_ reader: BufferReader) -> Photo? { + var _1: Api.Photo? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Photo + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.photos.Photo.photo(photo: _1!, users: _2!) + } + else { + return nil + } + } + + } + enum Photos: TypeConstructorDescription { + case photos(photos: [Api.Photo], users: [Api.User]) + case photosSlice(count: Int32, photos: [Api.Photo], users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photos(let photos, let users): + if boxed { + buffer.appendInt32(-1916114267) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .photosSlice(let count, let photos, let users): + if boxed { + buffer.appendInt32(352657236) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .photos(let photos, let users): + return ("photos", [("photos", photos), ("users", users)]) + case .photosSlice(let count, let photos, let users): + return ("photosSlice", [("count", count), ("photos", photos), ("users", users)]) + } + } + + static func parse_photos(_ reader: BufferReader) -> Photos? { + var _1: [Api.Photo]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.photos.Photos.photos(photos: _1!, users: _2!) + } + else { + return nil + } + } + static func parse_photosSlice(_ reader: BufferReader) -> Photos? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Photo]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.photos.Photos.photosSlice(count: _1!, photos: _2!, users: _3!) + } + else { + return nil + } + } + + } +} +} +extension Api { +struct phone { + enum PhoneCall: TypeConstructorDescription { + case phoneCall(phoneCall: Api.PhoneCall, users: [Api.User]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .phoneCall(let phoneCall, let users): + if boxed { + buffer.appendInt32(-326966976) + } + phoneCall.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .phoneCall(let phoneCall, let users): + return ("phoneCall", [("phoneCall", phoneCall), ("users", users)]) + } + } + + static func parse_phoneCall(_ reader: BufferReader) -> PhoneCall? { + var _1: Api.PhoneCall? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.PhoneCall + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.phone.PhoneCall.phoneCall(phoneCall: _1!, users: _2!) + } + else { + return nil + } + } + + } +} +} +extension Api { + struct functions { + struct messages { + static func getHistory(peer: Api.InputPeer, offsetId: Int32, offsetDate: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-591691168) + peer.serialize(buffer, true) + serializeInt32(offsetId, buffer: buffer, boxed: false) + serializeInt32(offsetDate, buffer: buffer, boxed: false) + serializeInt32(addOffset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(minId, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getHistory", parameters: [("peer", peer), ("offsetId", offsetId), ("offsetDate", offsetDate), ("addOffset", addOffset), ("limit", limit), ("maxId", maxId), ("minId", minId), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func readHistory(peer: Api.InputPeer, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(238054714) + peer.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.readHistory", parameters: [("peer", peer), ("maxId", maxId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedMessages? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedMessages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedMessages + } + return result + }) + } + + static func deleteHistory(flags: Int32, peer: Api.InputPeer, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(469850889) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.deleteHistory", parameters: [("flags", flags), ("peer", peer), ("maxId", maxId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedHistory? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedHistory + } + return result + }) + } + + static func deleteMessages(flags: Int32, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-443640366) + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.deleteMessages", parameters: [("flags", flags), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedMessages? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedMessages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedMessages + } + return result + }) + } + + static func receivedMessages(maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.ReceivedNotifyMessage]>) { + let buffer = Buffer() + buffer.appendInt32(94983360) + serializeInt32(maxId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.receivedMessages", parameters: [("maxId", maxId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.ReceivedNotifyMessage]? in + let reader = BufferReader(buffer) + var result: [Api.ReceivedNotifyMessage]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.ReceivedNotifyMessage.self) + } + return result + }) + } + + static func setTyping(peer: Api.InputPeer, action: Api.SendMessageAction) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1551737264) + peer.serialize(buffer, true) + action.serialize(buffer, true) + return (FunctionDescription(name: "messages.setTyping", parameters: [("peer", peer), ("action", action)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendMessage(flags: Int32, peer: Api.InputPeer, replyToMsgId: Int32?, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-91733382) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + serializeString(message, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.sendMessage", parameters: [("flags", flags), ("peer", peer), ("replyToMsgId", replyToMsgId), ("message", message), ("randomId", randomId), ("replyMarkup", replyMarkup), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func reportSpam(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-820669733) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.reportSpam", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPeerSettings(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(913498268) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.getPeerSettings", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.PeerSettings? in + let reader = BufferReader(buffer) + var result: Api.PeerSettings? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.PeerSettings + } + return result + }) + } + + static func getChats(id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1013621127) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.getChats", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getFullChat(chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(998448230) + serializeInt32(chatId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getFullChat", parameters: [("chatId", chatId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatFull? in + let reader = BufferReader(buffer) + var result: Api.messages.ChatFull? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.ChatFull + } + return result + }) + } + + static func editChatTitle(chatId: Int32, title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-599447467) + serializeInt32(chatId, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.editChatTitle", parameters: [("chatId", chatId), ("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func editChatPhoto(chatId: Int32, photo: Api.InputChatPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-900957736) + serializeInt32(chatId, buffer: buffer, boxed: false) + photo.serialize(buffer, true) + return (FunctionDescription(name: "messages.editChatPhoto", parameters: [("chatId", chatId), ("photo", photo)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func addChatUser(chatId: Int32, userId: Api.InputUser, fwdLimit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-106911223) + serializeInt32(chatId, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + serializeInt32(fwdLimit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.addChatUser", parameters: [("chatId", chatId), ("userId", userId), ("fwdLimit", fwdLimit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func deleteChatUser(chatId: Int32, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-530505962) + serializeInt32(chatId, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + return (FunctionDescription(name: "messages.deleteChatUser", parameters: [("chatId", chatId), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func createChat(users: [Api.InputUser], title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(164303470) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + serializeString(title, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.createChat", parameters: [("users", users), ("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func forwardMessage(peer: Api.InputPeer, id: Int32, randomId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(865483769) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.forwardMessage", parameters: [("peer", peer), ("id", id), ("randomId", randomId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getDhConfig(version: Int32, randomLength: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(651135312) + serializeInt32(version, buffer: buffer, boxed: false) + serializeInt32(randomLength, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getDhConfig", parameters: [("version", version), ("randomLength", randomLength)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.DhConfig? in + let reader = BufferReader(buffer) + var result: Api.messages.DhConfig? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.DhConfig + } + return result + }) + } + + static func requestEncryption(userId: Api.InputUser, randomId: Int32, gA: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-162681021) + userId.serialize(buffer, true) + serializeInt32(randomId, buffer: buffer, boxed: false) + serializeBytes(gA, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.requestEncryption", parameters: [("userId", userId), ("randomId", randomId), ("gA", gA)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EncryptedChat? in + let reader = BufferReader(buffer) + var result: Api.EncryptedChat? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EncryptedChat + } + return result + }) + } + + static func acceptEncryption(peer: Api.InputEncryptedChat, gB: Buffer, keyFingerprint: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1035731989) + peer.serialize(buffer, true) + serializeBytes(gB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.acceptEncryption", parameters: [("peer", peer), ("gB", gB), ("keyFingerprint", keyFingerprint)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EncryptedChat? in + let reader = BufferReader(buffer) + var result: Api.EncryptedChat? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EncryptedChat + } + return result + }) + } + + static func discardEncryption(chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-304536635) + serializeInt32(chatId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.discardEncryption", parameters: [("chatId", chatId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func setEncryptedTyping(peer: Api.InputEncryptedChat, typing: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2031374829) + peer.serialize(buffer, true) + typing.serialize(buffer, true) + return (FunctionDescription(name: "messages.setEncryptedTyping", parameters: [("peer", peer), ("typing", typing)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func readEncryptedHistory(peer: Api.InputEncryptedChat, maxDate: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2135648522) + peer.serialize(buffer, true) + serializeInt32(maxDate, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.readEncryptedHistory", parameters: [("peer", peer), ("maxDate", maxDate)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendEncrypted(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1451792525) + peer.serialize(buffer, true) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeBytes(data, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.sendEncrypted", parameters: [("peer", peer), ("randomId", randomId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in + let reader = BufferReader(buffer) + var result: Api.messages.SentEncryptedMessage? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage + } + return result + }) + } + + static func sendEncryptedFile(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer, file: Api.InputEncryptedFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1701831834) + peer.serialize(buffer, true) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeBytes(data, buffer: buffer, boxed: false) + file.serialize(buffer, true) + return (FunctionDescription(name: "messages.sendEncryptedFile", parameters: [("peer", peer), ("randomId", randomId), ("data", data), ("file", file)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in + let reader = BufferReader(buffer) + var result: Api.messages.SentEncryptedMessage? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage + } + return result + }) + } + + static func sendEncryptedService(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(852769188) + peer.serialize(buffer, true) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeBytes(data, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.sendEncryptedService", parameters: [("peer", peer), ("randomId", randomId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in + let reader = BufferReader(buffer) + var result: Api.messages.SentEncryptedMessage? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage + } + return result + }) + } + + static func receivedQueue(maxQts: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int64]>) { + let buffer = Buffer() + buffer.appendInt32(1436924774) + serializeInt32(maxQts, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.receivedQueue", parameters: [("maxQts", maxQts)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int64]? in + let reader = BufferReader(buffer) + var result: [Int64]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + return result + }) + } + + static func reportEncryptedSpam(peer: Api.InputEncryptedChat) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1259113487) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.reportEncryptedSpam", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func readMessageContents(id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(916930423) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.readMessageContents", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedMessages? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedMessages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedMessages + } + return result + }) + } + + static func getAllStickers(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(479598769) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getAllStickers", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AllStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.AllStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AllStickers + } + return result + }) + } + + static func checkChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1051570619) + serializeString(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.checkChatInvite", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ChatInvite? in + let reader = BufferReader(buffer) + var result: Api.ChatInvite? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.ChatInvite + } + return result + }) + } + + static func importChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1817183516) + serializeString(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.importChatInvite", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getStickerSet(stickerset: Api.InputStickerSet) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(639215886) + stickerset.serialize(buffer, true) + return (FunctionDescription(name: "messages.getStickerSet", parameters: [("stickerset", stickerset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.StickerSet? in + let reader = BufferReader(buffer) + var result: Api.messages.StickerSet? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.StickerSet + } + return result + }) + } + + static func installStickerSet(stickerset: Api.InputStickerSet, archived: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-946871200) + stickerset.serialize(buffer, true) + archived.serialize(buffer, true) + return (FunctionDescription(name: "messages.installStickerSet", parameters: [("stickerset", stickerset), ("archived", archived)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.StickerSetInstallResult? in + let reader = BufferReader(buffer) + var result: Api.messages.StickerSetInstallResult? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.StickerSetInstallResult + } + return result + }) + } + + static func uninstallStickerSet(stickerset: Api.InputStickerSet) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-110209570) + stickerset.serialize(buffer, true) + return (FunctionDescription(name: "messages.uninstallStickerSet", parameters: [("stickerset", stickerset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func startBot(bot: Api.InputUser, peer: Api.InputPeer, randomId: Int64, startParam: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-421563528) + bot.serialize(buffer, true) + peer.serialize(buffer, true) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeString(startParam, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.startBot", parameters: [("bot", bot), ("peer", peer), ("randomId", randomId), ("startParam", startParam)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getMessagesViews(peer: Api.InputPeer, id: [Int32], increment: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { + let buffer = Buffer() + buffer.appendInt32(-993483427) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + increment.serialize(buffer, true) + return (FunctionDescription(name: "messages.getMessagesViews", parameters: [("peer", peer), ("id", id), ("increment", increment)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in + let reader = BufferReader(buffer) + var result: [Int32]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + return result + }) + } + + static func editChatAdmin(chatId: Int32, userId: Api.InputUser, isAdmin: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1444503762) + serializeInt32(chatId, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + isAdmin.serialize(buffer, true) + return (FunctionDescription(name: "messages.editChatAdmin", parameters: [("chatId", chatId), ("userId", userId), ("isAdmin", isAdmin)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func migrateChat(chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(363051235) + serializeInt32(chatId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.migrateChat", parameters: [("chatId", chatId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func reorderStickerSets(flags: Int32, order: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2016638777) + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt64(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.reorderStickerSets", parameters: [("flags", flags), ("order", order)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getDocumentByHash(sha256: Buffer, size: Int32, mimeType: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(864953444) + serializeBytes(sha256, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getDocumentByHash", parameters: [("sha256", sha256), ("size", size), ("mimeType", mimeType)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Document? in + let reader = BufferReader(buffer) + var result: Api.Document? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Document + } + return result + }) + } + + static func searchGifs(q: String, offset: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1080395925) + serializeString(q, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.searchGifs", parameters: [("q", q), ("offset", offset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.FoundGifs? in + let reader = BufferReader(buffer) + var result: Api.messages.FoundGifs? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.FoundGifs + } + return result + }) + } + + static func getSavedGifs(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2084618926) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getSavedGifs", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SavedGifs? in + let reader = BufferReader(buffer) + var result: Api.messages.SavedGifs? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.SavedGifs + } + return result + }) + } + + static func saveGif(id: Api.InputDocument, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(846868683) + id.serialize(buffer, true) + unsave.serialize(buffer, true) + return (FunctionDescription(name: "messages.saveGif", parameters: [("id", id), ("unsave", unsave)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getInlineBotResults(flags: Int32, bot: Api.InputUser, peer: Api.InputPeer, geoPoint: Api.InputGeoPoint?, query: String, offset: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1364105629) + serializeInt32(flags, buffer: buffer, boxed: false) + bot.serialize(buffer, true) + peer.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {geoPoint!.serialize(buffer, true)} + serializeString(query, buffer: buffer, boxed: false) + serializeString(offset, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getInlineBotResults", parameters: [("flags", flags), ("bot", bot), ("peer", peer), ("geoPoint", geoPoint), ("query", query), ("offset", offset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.BotResults? in + let reader = BufferReader(buffer) + var result: Api.messages.BotResults? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.BotResults + } + return result + }) + } + + static func setInlineBotResults(flags: Int32, queryId: Int64, results: [Api.InputBotInlineResult], cacheTime: Int32, nextOffset: String?, switchPm: Api.InlineBotSwitchPM?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-346119674) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(results.count)) + for item in results { + item.serialize(buffer, true) + } + serializeInt32(cacheTime, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {switchPm!.serialize(buffer, true)} + return (FunctionDescription(name: "messages.setInlineBotResults", parameters: [("flags", flags), ("queryId", queryId), ("results", results), ("cacheTime", cacheTime), ("nextOffset", nextOffset), ("switchPm", switchPm)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendInlineBotResult(flags: Int32, peer: Api.InputPeer, replyToMsgId: Int32?, randomId: Int64, queryId: Int64, id: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1318189314) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + serializeString(id, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.sendInlineBotResult", parameters: [("flags", flags), ("peer", peer), ("replyToMsgId", replyToMsgId), ("randomId", randomId), ("queryId", queryId), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getMessageEditData(peer: Api.InputPeer, id: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-39416522) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getMessageEditData", parameters: [("peer", peer), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.MessageEditData? in + let reader = BufferReader(buffer) + var result: Api.messages.MessageEditData? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.MessageEditData + } + return result + }) + } + + static func getBotCallbackAnswer(flags: Int32, peer: Api.InputPeer, msgId: Int32, data: Buffer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2130010132) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(data!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.getBotCallbackAnswer", parameters: [("flags", flags), ("peer", peer), ("msgId", msgId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.BotCallbackAnswer? in + let reader = BufferReader(buffer) + var result: Api.messages.BotCallbackAnswer? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.BotCallbackAnswer + } + return result + }) + } + + static func setBotCallbackAnswer(flags: Int32, queryId: Int64, message: String?, url: String?, cacheTime: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-712043766) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(message!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + serializeInt32(cacheTime, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.setBotCallbackAnswer", parameters: [("flags", flags), ("queryId", queryId), ("message", message), ("url", url), ("cacheTime", cacheTime)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func saveDraft(flags: Int32, replyToMsgId: Int32?, peer: Api.InputPeer, message: String, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1137057461) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + peer.serialize(buffer, true) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.saveDraft", parameters: [("flags", flags), ("replyToMsgId", replyToMsgId), ("peer", peer), ("message", message), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAllDrafts() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1782549861) + + return (FunctionDescription(name: "messages.getAllDrafts", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getFeaturedStickers(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(766298703) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getFeaturedStickers", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.FeaturedStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.FeaturedStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.FeaturedStickers + } + return result + }) + } + + static func readFeaturedStickers(id: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1527873830) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt64(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.readFeaturedStickers", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getRecentStickers(flags: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1587647177) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getRecentStickers", parameters: [("flags", flags), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.RecentStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.RecentStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.RecentStickers + } + return result + }) + } + + static func saveRecentSticker(flags: Int32, id: Api.InputDocument, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(958863608) + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + unsave.serialize(buffer, true) + return (FunctionDescription(name: "messages.saveRecentSticker", parameters: [("flags", flags), ("id", id), ("unsave", unsave)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func clearRecentStickers(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1986437075) + serializeInt32(flags, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.clearRecentStickers", parameters: [("flags", flags)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getArchivedStickers(flags: Int32, offsetId: Int64, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1475442322) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(offsetId, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getArchivedStickers", parameters: [("flags", flags), ("offsetId", offsetId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ArchivedStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.ArchivedStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.ArchivedStickers + } + return result + }) + } + + static func getMaskStickers(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1706608543) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getMaskStickers", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AllStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.AllStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AllStickers + } + return result + }) + } + + static func getAttachedStickers(media: Api.InputStickeredMedia) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.StickerSetCovered]>) { + let buffer = Buffer() + buffer.appendInt32(-866424884) + media.serialize(buffer, true) + return (FunctionDescription(name: "messages.getAttachedStickers", parameters: [("media", media)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.StickerSetCovered]? in + let reader = BufferReader(buffer) + var result: [Api.StickerSetCovered]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self) + } + return result + }) + } + + static func setGameScore(flags: Int32, peer: Api.InputPeer, id: Int32, userId: Api.InputUser, score: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1896289088) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + serializeInt32(score, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.setGameScore", parameters: [("flags", flags), ("peer", peer), ("id", id), ("userId", userId), ("score", score)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func setInlineGameScore(flags: Int32, id: Api.InputBotInlineMessageID, userId: Api.InputUser, score: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(363700068) + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + userId.serialize(buffer, true) + serializeInt32(score, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.setInlineGameScore", parameters: [("flags", flags), ("id", id), ("userId", userId), ("score", score)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getGameHighScores(peer: Api.InputPeer, id: Int32, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-400399203) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + return (FunctionDescription(name: "messages.getGameHighScores", parameters: [("peer", peer), ("id", id), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.HighScores? in + let reader = BufferReader(buffer) + var result: Api.messages.HighScores? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.HighScores + } + return result + }) + } + + static func getInlineGameHighScores(id: Api.InputBotInlineMessageID, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(258170395) + id.serialize(buffer, true) + userId.serialize(buffer, true) + return (FunctionDescription(name: "messages.getInlineGameHighScores", parameters: [("id", id), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.HighScores? in + let reader = BufferReader(buffer) + var result: Api.messages.HighScores? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.HighScores + } + return result + }) + } + + static func getCommonChats(userId: Api.InputUser, maxId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(218777796) + userId.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getCommonChats", parameters: [("userId", userId), ("maxId", maxId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getAllChats(exceptIds: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-341307408) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(exceptIds.count)) + for item in exceptIds { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.getAllChats", parameters: [("exceptIds", exceptIds)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getWebPage(url: String, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(852135825) + serializeString(url, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getWebPage", parameters: [("url", url), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WebPage? in + let reader = BufferReader(buffer) + var result: Api.WebPage? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.WebPage + } + return result + }) + } + + static func setBotShippingResults(flags: Int32, queryId: Int64, error: String?, shippingOptions: [Api.ShippingOption]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-436833542) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(error!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(shippingOptions!.count)) + for item in shippingOptions! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.setBotShippingResults", parameters: [("flags", flags), ("queryId", queryId), ("error", error), ("shippingOptions", shippingOptions)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func setBotPrecheckoutResults(flags: Int32, queryId: Int64, error: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(163765653) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(queryId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(error!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.setBotPrecheckoutResults", parameters: [("flags", flags), ("queryId", queryId), ("error", error)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendScreenshotNotification(peer: Api.InputPeer, replyToMsgId: Int32, randomId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-914493408) + peer.serialize(buffer, true) + serializeInt32(replyToMsgId, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.sendScreenshotNotification", parameters: [("peer", peer), ("replyToMsgId", replyToMsgId), ("randomId", randomId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getFavedStickers(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(567151374) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getFavedStickers", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.FavedStickers? in + let reader = BufferReader(buffer) + var result: Api.messages.FavedStickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.FavedStickers + } + return result + }) + } + + static func faveSticker(id: Api.InputDocument, unfave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1174420133) + id.serialize(buffer, true) + unfave.serialize(buffer, true) + return (FunctionDescription(name: "messages.faveSticker", parameters: [("id", id), ("unfave", unfave)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getUnreadMentions(peer: Api.InputPeer, offsetId: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1180140658) + peer.serialize(buffer, true) + serializeInt32(offsetId, buffer: buffer, boxed: false) + serializeInt32(addOffset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(minId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getUnreadMentions", parameters: [("peer", peer), ("offsetId", offsetId), ("addOffset", addOffset), ("limit", limit), ("maxId", maxId), ("minId", minId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func readMentions(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(251759059) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.readMentions", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedHistory? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedHistory + } + return result + }) + } + + static func uploadMedia(peer: Api.InputPeer, media: Api.InputMedia) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1369162417) + peer.serialize(buffer, true) + media.serialize(buffer, true) + return (FunctionDescription(name: "messages.uploadMedia", parameters: [("peer", peer), ("media", media)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.MessageMedia? in + let reader = BufferReader(buffer) + var result: Api.MessageMedia? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.MessageMedia + } + return result + }) + } + + static func sendMultiMedia(flags: Int32, peer: Api.InputPeer, replyToMsgId: Int32?, multiMedia: [Api.InputSingleMedia]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(546656559) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(multiMedia.count)) + for item in multiMedia { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.sendMultiMedia", parameters: [("flags", flags), ("peer", peer), ("replyToMsgId", replyToMsgId), ("multiMedia", multiMedia)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func forwardMessages(flags: Int32, fromPeer: Api.InputPeer, id: [Int32], randomId: [Int64], toPeer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1888354709) + serializeInt32(flags, buffer: buffer, boxed: false) + fromPeer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomId.count)) + for item in randomId { + serializeInt64(item, buffer: buffer, boxed: false) + } + toPeer.serialize(buffer, true) + return (FunctionDescription(name: "messages.forwardMessages", parameters: [("flags", flags), ("fromPeer", fromPeer), ("id", id), ("randomId", randomId), ("toPeer", toPeer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func uploadEncryptedFile(peer: Api.InputEncryptedChat, file: Api.InputEncryptedFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1347929239) + peer.serialize(buffer, true) + file.serialize(buffer, true) + return (FunctionDescription(name: "messages.uploadEncryptedFile", parameters: [("peer", peer), ("file", file)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EncryptedFile? in + let reader = BufferReader(buffer) + var result: Api.EncryptedFile? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EncryptedFile + } + return result + }) + } + + static func getWebPagePreview(flags: Int32, message: String, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1956073268) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.getWebPagePreview", parameters: [("flags", flags), ("message", message), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.MessageMedia? in + let reader = BufferReader(buffer) + var result: Api.MessageMedia? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.MessageMedia + } + return result + }) + } + + static func sendMedia(flags: Int32, peer: Api.InputPeer, replyToMsgId: Int32?, media: Api.InputMedia, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1194252757) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(replyToMsgId!, buffer: buffer, boxed: false)} + media.serialize(buffer, true) + serializeString(message, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.sendMedia", parameters: [("flags", flags), ("peer", peer), ("replyToMsgId", replyToMsgId), ("media", media), ("message", message), ("randomId", randomId), ("replyMarkup", replyMarkup), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getMessages(id: [Api.InputMessage]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1673946374) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.getMessages", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func report(peer: Api.InputPeer, id: [Int32], reason: Api.ReportReason) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1115507112) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + reason.serialize(buffer, true) + return (FunctionDescription(name: "messages.report", parameters: [("peer", peer), ("id", id), ("reason", reason)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getRecentLocations(peer: Api.InputPeer, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1144759543) + peer.serialize(buffer, true) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getRecentLocations", parameters: [("peer", peer), ("limit", limit), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func search(flags: Int32, peer: Api.InputPeer, q: String, fromId: Api.InputUser?, filter: Api.MessagesFilter, minDate: Int32, maxDate: Int32, offsetId: Int32, addOffset: Int32, limit: Int32, maxId: Int32, minId: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2045448344) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeString(q, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {fromId!.serialize(buffer, true)} + filter.serialize(buffer, true) + serializeInt32(minDate, buffer: buffer, boxed: false) + serializeInt32(maxDate, buffer: buffer, boxed: false) + serializeInt32(offsetId, buffer: buffer, boxed: false) + serializeInt32(addOffset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(maxId, buffer: buffer, boxed: false) + serializeInt32(minId, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.search", parameters: [("flags", flags), ("peer", peer), ("q", q), ("fromId", fromId), ("filter", filter), ("minDate", minDate), ("maxDate", maxDate), ("offsetId", offsetId), ("addOffset", addOffset), ("limit", limit), ("maxId", maxId), ("minId", minId), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func toggleDialogPin(flags: Int32, peer: Api.InputDialogPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1489903017) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.toggleDialogPin", parameters: [("flags", flags), ("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPeerDialogs(peers: [Api.InputDialogPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-462373635) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(peers.count)) + for item in peers { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.getPeerDialogs", parameters: [("peers", peers)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.PeerDialogs? in + let reader = BufferReader(buffer) + var result: Api.messages.PeerDialogs? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.PeerDialogs + } + return result + }) + } + + static func searchStickerSets(flags: Int32, q: String, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1028140917) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(q, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.searchStickerSets", parameters: [("flags", flags), ("q", q), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.FoundStickerSets? in + let reader = BufferReader(buffer) + var result: Api.messages.FoundStickerSets? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.FoundStickerSets + } + return result + }) + } + + static func getStickers(emoticon: String, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(71126828) + serializeString(emoticon, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getStickers", parameters: [("emoticon", emoticon), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Stickers? in + let reader = BufferReader(buffer) + var result: Api.messages.Stickers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Stickers + } + return result + }) + } + + static func markDialogUnread(flags: Int32, peer: Api.InputDialogPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1031349873) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.markDialogUnread", parameters: [("flags", flags), ("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getDialogUnreadMarks() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.DialogPeer]>) { + let buffer = Buffer() + buffer.appendInt32(585256482) + + return (FunctionDescription(name: "messages.getDialogUnreadMarks", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.DialogPeer]? in + let reader = BufferReader(buffer) + var result: [Api.DialogPeer]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.DialogPeer.self) + } + return result + }) + } + + static func updatePinnedMessage(flags: Int32, peer: Api.InputPeer, id: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-760547348) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.updatePinnedMessage", parameters: [("flags", flags), ("peer", peer), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func sendVote(peer: Api.InputPeer, msgId: Int32, options: [Buffer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(283795844) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(options.count)) + for item in options { + serializeBytes(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.sendVote", parameters: [("peer", peer), ("msgId", msgId), ("options", options)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getPollResults(peer: Api.InputPeer, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1941660731) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getPollResults", parameters: [("peer", peer), ("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getOnlines(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1848369232) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.getOnlines", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ChatOnlines? in + let reader = BufferReader(buffer) + var result: Api.ChatOnlines? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.ChatOnlines + } + return result + }) + } + + static func getStatsURL(flags: Int32, peer: Api.InputPeer, params: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2127811866) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeString(params, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getStatsURL", parameters: [("flags", flags), ("peer", peer), ("params", params)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsURL? in + let reader = BufferReader(buffer) + var result: Api.StatsURL? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StatsURL + } + return result + }) + } + + static func editMessage(flags: Int32, peer: Api.InputPeer, id: Int32, message: String?, media: Api.InputMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-787025122) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 11) != 0 {serializeString(message!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 14) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.editMessage", parameters: [("flags", flags), ("peer", peer), ("id", id), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func editInlineBotMessage(flags: Int32, id: Api.InputBotInlineMessageID, message: String?, media: Api.InputMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2091549254) + serializeInt32(flags, buffer: buffer, boxed: false) + id.serialize(buffer, true) + if Int(flags) & Int(1 << 11) != 0 {serializeString(message!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 14) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)} + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + return (FunctionDescription(name: "messages.editInlineBotMessage", parameters: [("flags", flags), ("id", id), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func editChatAbout(peer: Api.InputPeer, about: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-554301545) + peer.serialize(buffer, true) + serializeString(about, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.editChatAbout", parameters: [("peer", peer), ("about", about)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func editChatDefaultBannedRights(peer: Api.InputPeer, bannedRights: Api.ChatBannedRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1517917375) + peer.serialize(buffer, true) + bannedRights.serialize(buffer, true) + return (FunctionDescription(name: "messages.editChatDefaultBannedRights", parameters: [("peer", peer), ("bannedRights", bannedRights)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func exportChatInvite(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(234312524) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in + let reader = BufferReader(buffer) + var result: Api.ExportedChatInvite? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite + } + return result + }) + } + + static func getEmojiKeywords(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(899735650) + serializeString(langCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getEmojiKeywords", parameters: [("langCode", langCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EmojiKeywordsDifference? in + let reader = BufferReader(buffer) + var result: Api.EmojiKeywordsDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EmojiKeywordsDifference + } + return result + }) + } + + static func getEmojiKeywordsDifference(langCode: String, fromVersion: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(352892591) + serializeString(langCode, buffer: buffer, boxed: false) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getEmojiKeywordsDifference", parameters: [("langCode", langCode), ("fromVersion", fromVersion)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EmojiKeywordsDifference? in + let reader = BufferReader(buffer) + var result: Api.EmojiKeywordsDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EmojiKeywordsDifference + } + return result + }) + } + + static func getEmojiURL(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-709817306) + serializeString(langCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getEmojiURL", parameters: [("langCode", langCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.EmojiURL? in + let reader = BufferReader(buffer) + var result: Api.EmojiURL? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.EmojiURL + } + return result + }) + } + + static func reorderPinnedDialogs(flags: Int32, folderId: Int32, order: [Api.InputDialogPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(991616823) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(folderId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.reorderPinnedDialogs", parameters: [("flags", flags), ("folderId", folderId), ("order", order)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPinnedDialogs(folderId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-692498958) + serializeInt32(folderId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getPinnedDialogs", parameters: [("folderId", folderId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.PeerDialogs? in + let reader = BufferReader(buffer) + var result: Api.messages.PeerDialogs? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.PeerDialogs + } + return result + }) + } + + static func getDialogs(flags: Int32, folderId: Int32?, offsetDate: Int32, offsetId: Int32, offsetPeer: Api.InputPeer, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1594999949) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + serializeInt32(offsetDate, buffer: buffer, boxed: false) + serializeInt32(offsetId, buffer: buffer, boxed: false) + offsetPeer.serialize(buffer, true) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getDialogs", parameters: [("flags", flags), ("folderId", folderId), ("offsetDate", offsetDate), ("offsetId", offsetId), ("offsetPeer", offsetPeer), ("limit", limit), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Dialogs? in + let reader = BufferReader(buffer) + var result: Api.messages.Dialogs? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Dialogs + } + return result + }) + } + + static func searchGlobal(q: String, offsetRate: Int32, offsetPeer: Api.InputPeer, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(259638801) + serializeString(q, buffer: buffer, boxed: false) + serializeInt32(offsetRate, buffer: buffer, boxed: false) + offsetPeer.serialize(buffer, true) + serializeInt32(offsetId, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.searchGlobal", parameters: [("q", q), ("offsetRate", offsetRate), ("offsetPeer", offsetPeer), ("offsetId", offsetId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func getSearchCounters(peer: Api.InputPeer, filters: [Api.MessagesFilter]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.messages.SearchCounter]>) { + let buffer = Buffer() + buffer.appendInt32(1932455680) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(filters.count)) + for item in filters { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.getSearchCounters", parameters: [("peer", peer), ("filters", filters)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.messages.SearchCounter]? in + let reader = BufferReader(buffer) + var result: [Api.messages.SearchCounter]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.messages.SearchCounter.self) + } + return result + }) + } + + static func requestUrlAuth(peer: Api.InputPeer, msgId: Int32, buttonId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-482388461) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + serializeInt32(buttonId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.requestUrlAuth", parameters: [("peer", peer), ("msgId", msgId), ("buttonId", buttonId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UrlAuthResult? in + let reader = BufferReader(buffer) + var result: Api.UrlAuthResult? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.UrlAuthResult + } + return result + }) + } + + static func acceptUrlAuth(flags: Int32, peer: Api.InputPeer, msgId: Int32, buttonId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-148247912) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + serializeInt32(buttonId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.acceptUrlAuth", parameters: [("flags", flags), ("peer", peer), ("msgId", msgId), ("buttonId", buttonId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UrlAuthResult? in + let reader = BufferReader(buffer) + var result: Api.UrlAuthResult? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.UrlAuthResult + } + return result + }) + } + + static func hidePeerSettingsBar(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1336717624) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.hidePeerSettingsBar", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + } + struct channels { + static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-871347913) + channel.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.readHistory", parameters: [("channel", channel), ("maxId", maxId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func deleteMessages(channel: Api.InputChannel, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2067661490) + channel.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "channels.deleteMessages", parameters: [("channel", channel), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedMessages? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedMessages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedMessages + } + return result + }) + } + + static func deleteUserHistory(channel: Api.InputChannel, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-787622117) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + return (FunctionDescription(name: "channels.deleteUserHistory", parameters: [("channel", channel), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AffectedHistory? in + let reader = BufferReader(buffer) + var result: Api.messages.AffectedHistory? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.AffectedHistory + } + return result + }) + } + + static func reportSpam(channel: Api.InputChannel, userId: Api.InputUser, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-32999408) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "channels.reportSpam", parameters: [("channel", channel), ("userId", userId), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getParticipant(channel: Api.InputChannel, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1416484774) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + return (FunctionDescription(name: "channels.getParticipant", parameters: [("channel", channel), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.channels.ChannelParticipant? in + let reader = BufferReader(buffer) + var result: Api.channels.ChannelParticipant? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.channels.ChannelParticipant + } + return result + }) + } + + static func getChannels(id: [Api.InputChannel]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(176122811) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "channels.getChannels", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getFullChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(141781513) + channel.serialize(buffer, true) + return (FunctionDescription(name: "channels.getFullChannel", parameters: [("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatFull? in + let reader = BufferReader(buffer) + var result: Api.messages.ChatFull? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.ChatFull + } + return result + }) + } + + static func createChannel(flags: Int32, title: String, about: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-192332417) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(about, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.createChannel", parameters: [("flags", flags), ("title", title), ("about", about)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func editTitle(channel: Api.InputChannel, title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1450044624) + channel.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.editTitle", parameters: [("channel", channel), ("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func editPhoto(channel: Api.InputChannel, photo: Api.InputChatPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-248621111) + channel.serialize(buffer, true) + photo.serialize(buffer, true) + return (FunctionDescription(name: "channels.editPhoto", parameters: [("channel", channel), ("photo", photo)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func checkUsername(channel: Api.InputChannel, username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(283557164) + channel.serialize(buffer, true) + serializeString(username, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.checkUsername", parameters: [("channel", channel), ("username", username)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func updateUsername(channel: Api.InputChannel, username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(890549214) + channel.serialize(buffer, true) + serializeString(username, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.updateUsername", parameters: [("channel", channel), ("username", username)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func joinChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(615851205) + channel.serialize(buffer, true) + return (FunctionDescription(name: "channels.joinChannel", parameters: [("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func leaveChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-130635115) + channel.serialize(buffer, true) + return (FunctionDescription(name: "channels.leaveChannel", parameters: [("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func inviteToChannel(channel: Api.InputChannel, users: [Api.InputUser]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(429865580) + channel.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "channels.inviteToChannel", parameters: [("channel", channel), ("users", users)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func kickFromChannel(channel: Api.InputChannel, userId: Api.InputUser, kicked: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1502421484) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + kicked.serialize(buffer, true) + return (FunctionDescription(name: "channels.kickFromChannel", parameters: [("channel", channel), ("userId", userId), ("kicked", kicked)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func deleteChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1072619549) + channel.serialize(buffer, true) + return (FunctionDescription(name: "channels.deleteChannel", parameters: [("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func toggleSignatures(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(527021574) + channel.serialize(buffer, true) + enabled.serialize(buffer, true) + return (FunctionDescription(name: "channels.toggleSignatures", parameters: [("channel", channel), ("enabled", enabled)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getAdminedPublicChannels() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1920105769) + + return (FunctionDescription(name: "channels.getAdminedPublicChannels", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getAdminLog(flags: Int32, channel: Api.InputChannel, q: String, eventsFilter: Api.ChannelAdminLogEventsFilter?, admins: [Api.InputUser]?, maxId: Int64, minId: Int64, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(870184064) + serializeInt32(flags, buffer: buffer, boxed: false) + channel.serialize(buffer, true) + serializeString(q, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {eventsFilter!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(admins!.count)) + for item in admins! { + item.serialize(buffer, true) + }} + serializeInt64(maxId, buffer: buffer, boxed: false) + serializeInt64(minId, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.getAdminLog", parameters: [("flags", flags), ("channel", channel), ("q", q), ("eventsFilter", eventsFilter), ("admins", admins), ("maxId", maxId), ("minId", minId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.channels.AdminLogResults? in + let reader = BufferReader(buffer) + var result: Api.channels.AdminLogResults? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.channels.AdminLogResults + } + return result + }) + } + + static func setStickers(channel: Api.InputChannel, stickerset: Api.InputStickerSet) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-359881479) + channel.serialize(buffer, true) + stickerset.serialize(buffer, true) + return (FunctionDescription(name: "channels.setStickers", parameters: [("channel", channel), ("stickerset", stickerset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func readMessageContents(channel: Api.InputChannel, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-357180360) + channel.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "channels.readMessageContents", parameters: [("channel", channel), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func deleteHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1355375294) + channel.serialize(buffer, true) + serializeInt32(maxId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.deleteHistory", parameters: [("channel", channel), ("maxId", maxId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func togglePreHistoryHidden(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-356796084) + channel.serialize(buffer, true) + enabled.serialize(buffer, true) + return (FunctionDescription(name: "channels.togglePreHistoryHidden", parameters: [("channel", channel), ("enabled", enabled)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getParticipants(channel: Api.InputChannel, filter: Api.ChannelParticipantsFilter, offset: Int32, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(306054633) + channel.serialize(buffer, true) + filter.serialize(buffer, true) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.getParticipants", parameters: [("channel", channel), ("filter", filter), ("offset", offset), ("limit", limit), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.channels.ChannelParticipants? in + let reader = BufferReader(buffer) + var result: Api.channels.ChannelParticipants? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.channels.ChannelParticipants + } + return result + }) + } + + static func exportMessageLink(channel: Api.InputChannel, id: Int32, grouped: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-826838685) + channel.serialize(buffer, true) + serializeInt32(id, buffer: buffer, boxed: false) + grouped.serialize(buffer, true) + return (FunctionDescription(name: "channels.exportMessageLink", parameters: [("channel", channel), ("id", id), ("grouped", grouped)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedMessageLink? in + let reader = BufferReader(buffer) + var result: Api.ExportedMessageLink? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.ExportedMessageLink + } + return result + }) + } + + static func getMessages(channel: Api.InputChannel, id: [Api.InputMessage]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1383294429) + channel.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "channels.getMessages", parameters: [("channel", channel), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } + + static func editAdmin(channel: Api.InputChannel, userId: Api.InputUser, adminRights: Api.ChatAdminRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1895338938) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + adminRights.serialize(buffer, true) + return (FunctionDescription(name: "channels.editAdmin", parameters: [("channel", channel), ("userId", userId), ("adminRights", adminRights)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func editBanned(channel: Api.InputChannel, userId: Api.InputUser, bannedRights: Api.ChatBannedRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1920559378) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + bannedRights.serialize(buffer, true) + return (FunctionDescription(name: "channels.editBanned", parameters: [("channel", channel), ("userId", userId), ("bannedRights", bannedRights)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getGroupsForDiscussion() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-170208392) + + return (FunctionDescription(name: "channels.getGroupsForDiscussion", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func getBroadcastsForDiscussion() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(445117188) + + return (FunctionDescription(name: "channels.getBroadcastsForDiscussion", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in + let reader = BufferReader(buffer) + var result: Api.messages.Chats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Chats + } + return result + }) + } + + static func setDiscussionGroup(broadcast: Api.InputChannel, group: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1079520178) + broadcast.serialize(buffer, true) + group.serialize(buffer, true) + return (FunctionDescription(name: "channels.setDiscussionGroup", parameters: [("broadcast", broadcast), ("group", group)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func editCreator(channel: Api.InputChannel, userId: Api.InputUser, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1892102881) + channel.serialize(buffer, true) + userId.serialize(buffer, true) + password.serialize(buffer, true) + return (FunctionDescription(name: "channels.editCreator", parameters: [("channel", channel), ("userId", userId), ("password", password)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + } + struct payments { + static func getPaymentForm(msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1712285883) + serializeInt32(msgId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getPaymentForm", parameters: [("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentForm? in + let reader = BufferReader(buffer) + var result: Api.payments.PaymentForm? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.PaymentForm + } + return result + }) + } + + static func getPaymentReceipt(msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1601001088) + serializeInt32(msgId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getPaymentReceipt", parameters: [("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentReceipt? in + let reader = BufferReader(buffer) + var result: Api.payments.PaymentReceipt? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.PaymentReceipt + } + return result + }) + } + + static func validateRequestedInfo(flags: Int32, msgId: Int32, info: Api.PaymentRequestedInfo) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1997180532) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(msgId, buffer: buffer, boxed: false) + info.serialize(buffer, true) + return (FunctionDescription(name: "payments.validateRequestedInfo", parameters: [("flags", flags), ("msgId", msgId), ("info", info)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.ValidatedRequestedInfo? in + let reader = BufferReader(buffer) + var result: Api.payments.ValidatedRequestedInfo? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.ValidatedRequestedInfo + } + return result + }) + } + + static func sendPaymentForm(flags: Int32, msgId: Int32, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(730364339) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(msgId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(requestedInfoId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(shippingOptionId!, buffer: buffer, boxed: false)} + credentials.serialize(buffer, true) + return (FunctionDescription(name: "payments.sendPaymentForm", parameters: [("flags", flags), ("msgId", msgId), ("requestedInfoId", requestedInfoId), ("shippingOptionId", shippingOptionId), ("credentials", credentials)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentResult? in + let reader = BufferReader(buffer) + var result: Api.payments.PaymentResult? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.PaymentResult + } + return result + }) + } + + static func getSavedInfo() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(578650699) + + return (FunctionDescription(name: "payments.getSavedInfo", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.SavedInfo? in + let reader = BufferReader(buffer) + var result: Api.payments.SavedInfo? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.SavedInfo + } + return result + }) + } + + static func clearSavedInfo(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-667062079) + serializeInt32(flags, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.clearSavedInfo", parameters: [("flags", flags)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + } + struct auth { + static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1877286395) + serializeString(phoneNumber, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.checkPhone", parameters: [("phoneNumber", phoneNumber)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.CheckedPhone? in + let reader = BufferReader(buffer) + var result: Api.auth.CheckedPhone? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.CheckedPhone + } + return result + }) + } + + static func sendCode(flags: Int32, phoneNumber: String, currentNumber: Api.Bool?, apiId: Int32, apiHash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2035355412) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {currentNumber!.serialize(buffer, true)} + serializeInt32(apiId, buffer: buffer, boxed: false) + serializeString(apiHash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.sendCode", parameters: [("flags", flags), ("phoneNumber", phoneNumber), ("currentNumber", currentNumber), ("apiId", apiId), ("apiHash", apiHash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.SentCode? in + let reader = BufferReader(buffer) + var result: Api.auth.SentCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.SentCode + } + return result + }) + } + + static func signUp(phoneNumber: String, phoneCodeHash: String, phoneCode: String, firstName: String, lastName: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(453408308) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(phoneCode, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.signUp", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash), ("phoneCode", phoneCode), ("firstName", firstName), ("lastName", lastName)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + + static func signIn(phoneNumber: String, phoneCodeHash: String, phoneCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1126886015) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(phoneCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.signIn", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash), ("phoneCode", phoneCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + + static func logOut() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1461180992) + + return (FunctionDescription(name: "auth.logOut", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func resetAuthorizations() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1616179942) + + return (FunctionDescription(name: "auth.resetAuthorizations", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendInvites(phoneNumbers: [String], message: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1998331287) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(phoneNumbers.count)) + for item in phoneNumbers { + serializeString(item, buffer: buffer, boxed: false) + } + serializeString(message, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.sendInvites", parameters: [("phoneNumbers", phoneNumbers), ("message", message)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func exportAuthorization(dcId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-440401971) + serializeInt32(dcId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.exportAuthorization", parameters: [("dcId", dcId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.ExportedAuthorization? in + let reader = BufferReader(buffer) + var result: Api.auth.ExportedAuthorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.ExportedAuthorization + } + return result + }) + } + + static func importAuthorization(id: Int32, bytes: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-470837741) + serializeInt32(id, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.importAuthorization", parameters: [("id", id), ("bytes", bytes)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + + static func bindTempAuthKey(permAuthKeyId: Int64, nonce: Int64, expiresAt: Int32, encryptedMessage: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-841733627) + serializeInt64(permAuthKeyId, buffer: buffer, boxed: false) + serializeInt64(nonce, buffer: buffer, boxed: false) + serializeInt32(expiresAt, buffer: buffer, boxed: false) + serializeBytes(encryptedMessage, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.bindTempAuthKey", parameters: [("permAuthKeyId", permAuthKeyId), ("nonce", nonce), ("expiresAt", expiresAt), ("encryptedMessage", encryptedMessage)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func importBotAuthorization(flags: Int32, apiId: Int32, apiHash: String, botAuthToken: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1738800940) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(apiId, buffer: buffer, boxed: false) + serializeString(apiHash, buffer: buffer, boxed: false) + serializeString(botAuthToken, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.importBotAuthorization", parameters: [("flags", flags), ("apiId", apiId), ("apiHash", apiHash), ("botAuthToken", botAuthToken)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + + static func requestPasswordRecovery() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-661144474) + + return (FunctionDescription(name: "auth.requestPasswordRecovery", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.PasswordRecovery? in + let reader = BufferReader(buffer) + var result: Api.auth.PasswordRecovery? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.PasswordRecovery + } + return result + }) + } + + static func recoverPassword(code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1319464594) + serializeString(code, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.recoverPassword", parameters: [("code", code)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + + static func resendCode(phoneNumber: String, phoneCodeHash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1056025023) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.resendCode", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.SentCode? in + let reader = BufferReader(buffer) + var result: Api.auth.SentCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.SentCode + } + return result + }) + } + + static func cancelCode(phoneNumber: String, phoneCodeHash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(520357240) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "auth.cancelCode", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func dropTempAuthKeys(exceptAuthKeys: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1907842680) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(exceptAuthKeys.count)) + for item in exceptAuthKeys { + serializeInt64(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "auth.dropTempAuthKeys", parameters: [("exceptAuthKeys", exceptAuthKeys)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func checkPassword(password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-779399914) + password.serialize(buffer, true) + return (FunctionDescription(name: "auth.checkPassword", parameters: [("password", password)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } + } + struct bots { + static func sendCustomRequest(customMethod: String, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1440257555) + serializeString(customMethod, buffer: buffer, boxed: false) + params.serialize(buffer, true) + return (FunctionDescription(name: "bots.sendCustomRequest", parameters: [("customMethod", customMethod), ("params", params)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.DataJSON? in + let reader = BufferReader(buffer) + var result: Api.DataJSON? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.DataJSON + } + return result + }) + } + + static func answerWebhookJSONQuery(queryId: Int64, data: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-434028723) + serializeInt64(queryId, buffer: buffer, boxed: false) + data.serialize(buffer, true) + return (FunctionDescription(name: "bots.answerWebhookJSONQuery", parameters: [("queryId", queryId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + } + struct users { + static func getUsers(id: [Api.InputUser]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.User]>) { + let buffer = Buffer() + buffer.appendInt32(227648840) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "users.getUsers", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.User]? in + let reader = BufferReader(buffer) + var result: [Api.User]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + return result + }) + } + + static func setSecureValueErrors(id: Api.InputUser, errors: [Api.SecureValueError]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1865902923) + id.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(errors.count)) + for item in errors { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "users.setSecureValueErrors", parameters: [("id", id), ("errors", errors)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getFullUser(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-902781519) + id.serialize(buffer, true) + return (FunctionDescription(name: "users.getFullUser", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UserFull? in + let reader = BufferReader(buffer) + var result: Api.UserFull? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.UserFull + } + return result + }) + } + } + struct contacts { + static func getStatuses() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.ContactStatus]>) { + let buffer = Buffer() + buffer.appendInt32(-995929106) + + return (FunctionDescription(name: "contacts.getStatuses", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.ContactStatus]? in + let reader = BufferReader(buffer) + var result: [Api.ContactStatus]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.ContactStatus.self) + } + return result + }) + } + + static func block(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(858475004) + id.serialize(buffer, true) + return (FunctionDescription(name: "contacts.block", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func unblock(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-448724803) + id.serialize(buffer, true) + return (FunctionDescription(name: "contacts.unblock", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getBlocked(offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-176409329) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.getBlocked", parameters: [("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.Blocked? in + let reader = BufferReader(buffer) + var result: Api.contacts.Blocked? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.Blocked + } + return result + }) + } + + static func exportCard() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { + let buffer = Buffer() + buffer.appendInt32(-2065352905) + + return (FunctionDescription(name: "contacts.exportCard", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in + let reader = BufferReader(buffer) + var result: [Int32]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + return result + }) + } + + static func importCard(exportCard: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1340184318) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(exportCard.count)) + for item in exportCard { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "contacts.importCard", parameters: [("exportCard", exportCard)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in + let reader = BufferReader(buffer) + var result: Api.User? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.User + } + return result + }) + } + + static func search(q: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(301470424) + serializeString(q, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.search", parameters: [("q", q), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.Found? in + let reader = BufferReader(buffer) + var result: Api.contacts.Found? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.Found + } + return result + }) + } + + static func resolveUsername(username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-113456221) + serializeString(username, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.resolveUsername", parameters: [("username", username)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.ResolvedPeer? in + let reader = BufferReader(buffer) + var result: Api.contacts.ResolvedPeer? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.ResolvedPeer + } + return result + }) + } + + static func getTopPeers(flags: Int32, offset: Int32, limit: Int32, hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-728224331) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.getTopPeers", parameters: [("flags", flags), ("offset", offset), ("limit", limit), ("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.TopPeers? in + let reader = BufferReader(buffer) + var result: Api.contacts.TopPeers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.TopPeers + } + return result + }) + } + + static func resetTopPeerRating(category: Api.TopPeerCategory, peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(451113900) + category.serialize(buffer, true) + peer.serialize(buffer, true) + return (FunctionDescription(name: "contacts.resetTopPeerRating", parameters: [("category", category), ("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func importContacts(contacts: [Api.InputContact]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(746589157) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(contacts.count)) + for item in contacts { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "contacts.importContacts", parameters: [("contacts", contacts)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.ImportedContacts? in + let reader = BufferReader(buffer) + var result: Api.contacts.ImportedContacts? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.ImportedContacts + } + return result + }) + } + + static func resetSaved() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2020263951) + + return (FunctionDescription(name: "contacts.resetSaved", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getContacts(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1071414113) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.getContacts", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.contacts.Contacts? in + let reader = BufferReader(buffer) + var result: Api.contacts.Contacts? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.contacts.Contacts + } + return result + }) + } + + static func toggleTopPeers(enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2062238246) + enabled.serialize(buffer, true) + return (FunctionDescription(name: "contacts.toggleTopPeers", parameters: [("enabled", enabled)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getContactIDs(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { + let buffer = Buffer() + buffer.appendInt32(749357634) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.getContactIDs", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in + let reader = BufferReader(buffer) + var result: [Int32]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + return result + }) + } + + static func addContact(id: Api.InputUser, firstName: String, lastName: String, phone: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2035792455) + id.serialize(buffer, true) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeString(phone, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.addContact", parameters: [("id", id), ("firstName", firstName), ("lastName", lastName), ("phone", phone)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func acceptContact(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-130964977) + id.serialize(buffer, true) + return (FunctionDescription(name: "contacts.acceptContact", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func deleteContacts(id: [Api.InputUser]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(157945344) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "contacts.deleteContacts", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getLocated(geoPoint: Api.InputGeoPoint, radius: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-261936023) + geoPoint.serialize(buffer, true) + serializeInt32(radius, buffer: buffer, boxed: false) + return (FunctionDescription(name: "contacts.getLocated", parameters: [("geoPoint", geoPoint), ("radius", radius)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + } + struct help { + static func getConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-990308245) + + return (FunctionDescription(name: "help.getConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Config? in + let reader = BufferReader(buffer) + var result: Api.Config? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Config + } + return result + }) + } + + static func getNearestDc() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(531836966) + + return (FunctionDescription(name: "help.getNearestDc", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.NearestDc? in + let reader = BufferReader(buffer) + var result: Api.NearestDc? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.NearestDc + } + return result + }) + } + + static func getAppUpdate() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1372724842) + + return (FunctionDescription(name: "help.getAppUpdate", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.AppUpdate? in + let reader = BufferReader(buffer) + var result: Api.help.AppUpdate? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.AppUpdate + } + return result + }) + } + + static func getInviteText() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1295590211) + + return (FunctionDescription(name: "help.getInviteText", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.InviteText? in + let reader = BufferReader(buffer) + var result: Api.help.InviteText? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.InviteText + } + return result + }) + } + + static func getSupport() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1663104819) + + return (FunctionDescription(name: "help.getSupport", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.Support? in + let reader = BufferReader(buffer) + var result: Api.help.Support? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.Support + } + return result + }) + } + + static func getAppChangelog(prevAppVersion: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1877938321) + serializeString(prevAppVersion, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getAppChangelog", parameters: [("prevAppVersion", prevAppVersion)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func setBotUpdatesStatus(pendingUpdatesCount: Int32, message: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-333262899) + serializeInt32(pendingUpdatesCount, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.setBotUpdatesStatus", parameters: [("pendingUpdatesCount", pendingUpdatesCount), ("message", message)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getCdnConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1375900482) + + return (FunctionDescription(name: "help.getCdnConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.CdnConfig? in + let reader = BufferReader(buffer) + var result: Api.CdnConfig? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.CdnConfig + } + return result + }) + } + + static func test() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1058929929) + + return (FunctionDescription(name: "help.test", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getRecentMeUrls(referer: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1036054804) + serializeString(referer, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getRecentMeUrls", parameters: [("referer", referer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.RecentMeUrls? in + let reader = BufferReader(buffer) + var result: Api.help.RecentMeUrls? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.RecentMeUrls + } + return result + }) + } + + static func getProxyData() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1031231713) + + return (FunctionDescription(name: "help.getProxyData", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.ProxyData? in + let reader = BufferReader(buffer) + var result: Api.help.ProxyData? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.ProxyData + } + return result + }) + } + + static func getTermsOfServiceUpdate() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(749019089) + + return (FunctionDescription(name: "help.getTermsOfServiceUpdate", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.TermsOfServiceUpdate? in + let reader = BufferReader(buffer) + var result: Api.help.TermsOfServiceUpdate? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.TermsOfServiceUpdate + } + return result + }) + } + + static func acceptTermsOfService(id: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-294455398) + id.serialize(buffer, true) + return (FunctionDescription(name: "help.acceptTermsOfService", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getDeepLinkInfo(path: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1072547679) + serializeString(path, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getDeepLinkInfo", parameters: [("path", path)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.DeepLinkInfo? in + let reader = BufferReader(buffer) + var result: Api.help.DeepLinkInfo? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.DeepLinkInfo + } + return result + }) + } + + static func getPassportConfig(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-966677240) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getPassportConfig", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.PassportConfig? in + let reader = BufferReader(buffer) + var result: Api.help.PassportConfig? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.PassportConfig + } + return result + }) + } + + static func getAppConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1735311088) + + return (FunctionDescription(name: "help.getAppConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.JSONValue? in + let reader = BufferReader(buffer) + var result: Api.JSONValue? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.JSONValue + } + return result + }) + } + + static func saveAppLog(events: [Api.InputAppEvent]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1862465352) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(events.count)) + for item in events { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "help.saveAppLog", parameters: [("events", events)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + } + struct updates { + static func getState() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-304838614) + + return (FunctionDescription(name: "updates.getState", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.updates.State? in + let reader = BufferReader(buffer) + var result: Api.updates.State? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.updates.State + } + return result + }) + } + + static func getDifference(flags: Int32, pts: Int32, ptsTotalLimit: Int32?, date: Int32, qts: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(630429265) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(pts, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ptsTotalLimit!, buffer: buffer, boxed: false)} + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(qts, buffer: buffer, boxed: false) + return (FunctionDescription(name: "updates.getDifference", parameters: [("flags", flags), ("pts", pts), ("ptsTotalLimit", ptsTotalLimit), ("date", date), ("qts", qts)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.updates.Difference? in + let reader = BufferReader(buffer) + var result: Api.updates.Difference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.updates.Difference + } + return result + }) + } + + static func getChannelDifference(flags: Int32, channel: Api.InputChannel, filter: Api.ChannelMessagesFilter, pts: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(51854712) + serializeInt32(flags, buffer: buffer, boxed: false) + channel.serialize(buffer, true) + filter.serialize(buffer, true) + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "updates.getChannelDifference", parameters: [("flags", flags), ("channel", channel), ("filter", filter), ("pts", pts), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.updates.ChannelDifference? in + let reader = BufferReader(buffer) + var result: Api.updates.ChannelDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.updates.ChannelDifference + } + return result + }) + } + } + struct folders { + static func editPeerFolders(folderPeers: [Api.InputFolderPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1749536939) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(folderPeers.count)) + for item in folderPeers { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "folders.editPeerFolders", parameters: [("folderPeers", folderPeers)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func deleteFolder(folderId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(472471681) + serializeInt32(folderId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "folders.deleteFolder", parameters: [("folderId", folderId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + } + struct upload { + static func saveFilePart(fileId: Int64, filePart: Int32, bytes: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1291540959) + serializeInt64(fileId, buffer: buffer, boxed: false) + serializeInt32(filePart, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.saveFilePart", parameters: [("fileId", fileId), ("filePart", filePart), ("bytes", bytes)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getFile(location: Api.InputFileLocation, offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-475607115) + location.serialize(buffer, true) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.getFile", parameters: [("location", location), ("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.upload.File? in + let reader = BufferReader(buffer) + var result: Api.upload.File? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.upload.File + } + return result + }) + } + + static func saveBigFilePart(fileId: Int64, filePart: Int32, fileTotalParts: Int32, bytes: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-562337987) + serializeInt64(fileId, buffer: buffer, boxed: false) + serializeInt32(filePart, buffer: buffer, boxed: false) + serializeInt32(fileTotalParts, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.saveBigFilePart", parameters: [("fileId", fileId), ("filePart", filePart), ("fileTotalParts", fileTotalParts), ("bytes", bytes)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getWebFile(location: Api.InputWebFileLocation, offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(619086221) + location.serialize(buffer, true) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.getWebFile", parameters: [("location", location), ("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.upload.WebFile? in + let reader = BufferReader(buffer) + var result: Api.upload.WebFile? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.upload.WebFile + } + return result + }) + } + + static func getCdnFile(fileToken: Buffer, offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(536919235) + serializeBytes(fileToken, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.getCdnFile", parameters: [("fileToken", fileToken), ("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.upload.CdnFile? in + let reader = BufferReader(buffer) + var result: Api.upload.CdnFile? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.upload.CdnFile + } + return result + }) + } + + static func reuploadCdnFile(fileToken: Buffer, requestToken: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.FileHash]>) { + let buffer = Buffer() + buffer.appendInt32(-1691921240) + serializeBytes(fileToken, buffer: buffer, boxed: false) + serializeBytes(requestToken, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.reuploadCdnFile", parameters: [("fileToken", fileToken), ("requestToken", requestToken)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.FileHash]? in + let reader = BufferReader(buffer) + var result: [Api.FileHash]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.FileHash.self) + } + return result + }) + } + + static func getCdnFileHashes(fileToken: Buffer, offset: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.FileHash]>) { + let buffer = Buffer() + buffer.appendInt32(1302676017) + serializeBytes(fileToken, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.getCdnFileHashes", parameters: [("fileToken", fileToken), ("offset", offset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.FileHash]? in + let reader = BufferReader(buffer) + var result: [Api.FileHash]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.FileHash.self) + } + return result + }) + } + + static func getFileHashes(location: Api.InputFileLocation, offset: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.FileHash]>) { + let buffer = Buffer() + buffer.appendInt32(-956147407) + location.serialize(buffer, true) + serializeInt32(offset, buffer: buffer, boxed: false) + return (FunctionDescription(name: "upload.getFileHashes", parameters: [("location", location), ("offset", offset)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.FileHash]? in + let reader = BufferReader(buffer) + var result: [Api.FileHash]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.FileHash.self) + } + return result + }) + } + } + struct account { + static func updateNotifySettings(peer: Api.InputNotifyPeer, settings: Api.InputPeerNotifySettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2067899501) + peer.serialize(buffer, true) + settings.serialize(buffer, true) + return (FunctionDescription(name: "account.updateNotifySettings", parameters: [("peer", peer), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getNotifySettings(peer: Api.InputNotifyPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(313765169) + peer.serialize(buffer, true) + return (FunctionDescription(name: "account.getNotifySettings", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.PeerNotifySettings? in + let reader = BufferReader(buffer) + var result: Api.PeerNotifySettings? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + } + return result + }) + } + + static func resetNotifySettings() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-612493497) + + return (FunctionDescription(name: "account.resetNotifySettings", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func updateProfile(flags: Int32, firstName: String?, lastName: String?, about: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2018596725) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(firstName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(lastName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(about!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "account.updateProfile", parameters: [("flags", flags), ("firstName", firstName), ("lastName", lastName), ("about", about)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in + let reader = BufferReader(buffer) + var result: Api.User? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.User + } + return result + }) + } + + static func updateStatus(offline: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1713919532) + offline.serialize(buffer, true) + return (FunctionDescription(name: "account.updateStatus", parameters: [("offline", offline)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func reportPeer(peer: Api.InputPeer, reason: Api.ReportReason) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1374118561) + peer.serialize(buffer, true) + reason.serialize(buffer, true) + return (FunctionDescription(name: "account.reportPeer", parameters: [("peer", peer), ("reason", reason)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func checkUsername(username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(655677548) + serializeString(username, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.checkUsername", parameters: [("username", username)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func updateUsername(username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1040964988) + serializeString(username, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.updateUsername", parameters: [("username", username)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in + let reader = BufferReader(buffer) + var result: Api.User? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.User + } + return result + }) + } + + static func getPrivacy(key: Api.InputPrivacyKey) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-623130288) + key.serialize(buffer, true) + return (FunctionDescription(name: "account.getPrivacy", parameters: [("key", key)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.PrivacyRules? in + let reader = BufferReader(buffer) + var result: Api.account.PrivacyRules? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.PrivacyRules + } + return result + }) + } + + static func setPrivacy(key: Api.InputPrivacyKey, rules: [Api.InputPrivacyRule]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-906486552) + key.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(rules.count)) + for item in rules { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "account.setPrivacy", parameters: [("key", key), ("rules", rules)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.PrivacyRules? in + let reader = BufferReader(buffer) + var result: Api.account.PrivacyRules? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.PrivacyRules + } + return result + }) + } + + static func deleteAccount(reason: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1099779595) + serializeString(reason, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.deleteAccount", parameters: [("reason", reason)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAccountTTL() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(150761757) + + return (FunctionDescription(name: "account.getAccountTTL", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.AccountDaysTTL? in + let reader = BufferReader(buffer) + var result: Api.AccountDaysTTL? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.AccountDaysTTL + } + return result + }) + } + + static func setAccountTTL(ttl: Api.AccountDaysTTL) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(608323678) + ttl.serialize(buffer, true) + return (FunctionDescription(name: "account.setAccountTTL", parameters: [("ttl", ttl)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendChangePhoneCode(flags: Int32, phoneNumber: String, currentNumber: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(149257707) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {currentNumber!.serialize(buffer, true)} + return (FunctionDescription(name: "account.sendChangePhoneCode", parameters: [("flags", flags), ("phoneNumber", phoneNumber), ("currentNumber", currentNumber)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.SentCode? in + let reader = BufferReader(buffer) + var result: Api.auth.SentCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.SentCode + } + return result + }) + } + + static func changePhone(phoneNumber: String, phoneCodeHash: String, phoneCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1891839707) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(phoneCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.changePhone", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash), ("phoneCode", phoneCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in + let reader = BufferReader(buffer) + var result: Api.User? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.User + } + return result + }) + } + + static func updateDeviceLocked(period: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(954152242) + serializeInt32(period, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.updateDeviceLocked", parameters: [("period", period)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAuthorizations() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-484392616) + + return (FunctionDescription(name: "account.getAuthorizations", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.Authorizations? in + let reader = BufferReader(buffer) + var result: Api.account.Authorizations? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.Authorizations + } + return result + }) + } + + static func resetAuthorization(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-545786948) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.resetAuthorization", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPassword() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1418342645) + + return (FunctionDescription(name: "account.getPassword", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.Password? in + let reader = BufferReader(buffer) + var result: Api.account.Password? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.Password + } + return result + }) + } + + static func sendConfirmPhoneCode(flags: Int32, hash: String, currentNumber: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(353818557) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {currentNumber!.serialize(buffer, true)} + return (FunctionDescription(name: "account.sendConfirmPhoneCode", parameters: [("flags", flags), ("hash", hash), ("currentNumber", currentNumber)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.SentCode? in + let reader = BufferReader(buffer) + var result: Api.auth.SentCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.SentCode + } + return result + }) + } + + static func confirmPhone(phoneCodeHash: String, phoneCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1596029123) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(phoneCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.confirmPhone", parameters: [("phoneCodeHash", phoneCodeHash), ("phoneCode", phoneCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func unregisterDevice(tokenType: Int32, token: String, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(813089983) + serializeInt32(tokenType, buffer: buffer, boxed: false) + serializeString(token, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(otherUids.count)) + for item in otherUids { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "account.unregisterDevice", parameters: [("tokenType", tokenType), ("token", token), ("otherUids", otherUids)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getWebAuthorizations() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(405695855) + + return (FunctionDescription(name: "account.getWebAuthorizations", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.WebAuthorizations? in + let reader = BufferReader(buffer) + var result: Api.account.WebAuthorizations? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.WebAuthorizations + } + return result + }) + } + + static func resetWebAuthorization(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(755087855) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.resetWebAuthorization", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func resetWebAuthorizations() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1747789204) + + return (FunctionDescription(name: "account.resetWebAuthorizations", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func registerDevice(tokenType: Int32, token: String, appSandbox: Api.Bool, secret: Buffer, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1555998096) + serializeInt32(tokenType, buffer: buffer, boxed: false) + serializeString(token, buffer: buffer, boxed: false) + appSandbox.serialize(buffer, true) + serializeBytes(secret, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(otherUids.count)) + for item in otherUids { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "account.registerDevice", parameters: [("tokenType", tokenType), ("token", token), ("appSandbox", appSandbox), ("secret", secret), ("otherUids", otherUids)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAllSecureValues() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.SecureValue]>) { + let buffer = Buffer() + buffer.appendInt32(-1299661699) + + return (FunctionDescription(name: "account.getAllSecureValues", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.SecureValue]? in + let reader = BufferReader(buffer) + var result: [Api.SecureValue]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) + } + return result + }) + } + + static func getSecureValue(types: [Api.SecureValueType]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.SecureValue]>) { + let buffer = Buffer() + buffer.appendInt32(1936088002) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "account.getSecureValue", parameters: [("types", types)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.SecureValue]? in + let reader = BufferReader(buffer) + var result: [Api.SecureValue]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) + } + return result + }) + } + + static func saveSecureValue(value: Api.InputSecureValue, secureSecretId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1986010339) + value.serialize(buffer, true) + serializeInt64(secureSecretId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.saveSecureValue", parameters: [("value", value), ("secureSecretId", secureSecretId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.SecureValue? in + let reader = BufferReader(buffer) + var result: Api.SecureValue? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.SecureValue + } + return result + }) + } + + static func deleteSecureValue(types: [Api.SecureValueType]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1199522741) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "account.deleteSecureValue", parameters: [("types", types)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAuthorizationForm(botId: Int32, scope: String, publicKey: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1200903967) + serializeInt32(botId, buffer: buffer, boxed: false) + serializeString(scope, buffer: buffer, boxed: false) + serializeString(publicKey, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getAuthorizationForm", parameters: [("botId", botId), ("scope", scope), ("publicKey", publicKey)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.AuthorizationForm? in + let reader = BufferReader(buffer) + var result: Api.account.AuthorizationForm? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.AuthorizationForm + } + return result + }) + } + + static func acceptAuthorization(botId: Int32, scope: String, publicKey: String, valueHashes: [Api.SecureValueHash], credentials: Api.SecureCredentialsEncrypted) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-419267436) + serializeInt32(botId, buffer: buffer, boxed: false) + serializeString(scope, buffer: buffer, boxed: false) + serializeString(publicKey, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(valueHashes.count)) + for item in valueHashes { + item.serialize(buffer, true) + } + credentials.serialize(buffer, true) + return (FunctionDescription(name: "account.acceptAuthorization", parameters: [("botId", botId), ("scope", scope), ("publicKey", publicKey), ("valueHashes", valueHashes), ("credentials", credentials)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendVerifyPhoneCode(flags: Int32, phoneNumber: String, currentNumber: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2110553932) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {currentNumber!.serialize(buffer, true)} + return (FunctionDescription(name: "account.sendVerifyPhoneCode", parameters: [("flags", flags), ("phoneNumber", phoneNumber), ("currentNumber", currentNumber)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.SentCode? in + let reader = BufferReader(buffer) + var result: Api.auth.SentCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.SentCode + } + return result + }) + } + + static func verifyPhone(phoneNumber: String, phoneCodeHash: String, phoneCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1305716726) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(phoneCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.verifyPhone", parameters: [("phoneNumber", phoneNumber), ("phoneCodeHash", phoneCodeHash), ("phoneCode", phoneCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func sendVerifyEmailCode(email: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1880182943) + serializeString(email, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.sendVerifyEmailCode", parameters: [("email", email)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.SentEmailCode? in + let reader = BufferReader(buffer) + var result: Api.account.SentEmailCode? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.SentEmailCode + } + return result + }) + } + + static func verifyEmail(email: String, code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-323339813) + serializeString(email, buffer: buffer, boxed: false) + serializeString(code, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.verifyEmail", parameters: [("email", email), ("code", code)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getTmpPassword(password: Api.InputCheckPasswordSRP, period: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1151208273) + password.serialize(buffer, true) + serializeInt32(period, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getTmpPassword", parameters: [("password", password), ("period", period)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.TmpPassword? in + let reader = BufferReader(buffer) + var result: Api.account.TmpPassword? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.TmpPassword + } + return result + }) + } + + static func updatePasswordSettings(password: Api.InputCheckPasswordSRP, newSettings: Api.account.PasswordInputSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1516564433) + password.serialize(buffer, true) + newSettings.serialize(buffer, true) + return (FunctionDescription(name: "account.updatePasswordSettings", parameters: [("password", password), ("newSettings", newSettings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPasswordSettings(password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1663767815) + password.serialize(buffer, true) + return (FunctionDescription(name: "account.getPasswordSettings", parameters: [("password", password)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.PasswordSettings? in + let reader = BufferReader(buffer) + var result: Api.account.PasswordSettings? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.PasswordSettings + } + return result + }) + } + + static func confirmPasswordEmail(code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1881204448) + serializeString(code, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.confirmPasswordEmail", parameters: [("code", code)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func resendPasswordEmail() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2055154197) + + return (FunctionDescription(name: "account.resendPasswordEmail", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func cancelPasswordEmail() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1043606090) + + return (FunctionDescription(name: "account.cancelPasswordEmail", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getContactSignUpNotification() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1626880216) + + return (FunctionDescription(name: "account.getContactSignUpNotification", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func setContactSignUpNotification(silent: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-806076575) + silent.serialize(buffer, true) + return (FunctionDescription(name: "account.setContactSignUpNotification", parameters: [("silent", silent)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getNotifyExceptions(flags: Int32, peer: Api.InputNotifyPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1398240377) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {peer!.serialize(buffer, true)} + return (FunctionDescription(name: "account.getNotifyExceptions", parameters: [("flags", flags), ("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func getWallPapers(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1430579357) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getWallPapers", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.WallPapers? in + let reader = BufferReader(buffer) + var result: Api.account.WallPapers? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.WallPapers + } + return result + }) + } + + static func uploadWallPaper(file: Api.InputFile, mimeType: String, settings: Api.WallPaperSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-578472351) + file.serialize(buffer, true) + serializeString(mimeType, buffer: buffer, boxed: false) + settings.serialize(buffer, true) + return (FunctionDescription(name: "account.uploadWallPaper", parameters: [("file", file), ("mimeType", mimeType), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WallPaper? in + let reader = BufferReader(buffer) + var result: Api.WallPaper? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.WallPaper + } + return result + }) + } + + static func getWallPaper(wallpaper: Api.InputWallPaper) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-57811990) + wallpaper.serialize(buffer, true) + return (FunctionDescription(name: "account.getWallPaper", parameters: [("wallpaper", wallpaper)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.WallPaper? in + let reader = BufferReader(buffer) + var result: Api.WallPaper? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.WallPaper + } + return result + }) + } + + static func saveWallPaper(wallpaper: Api.InputWallPaper, unsave: Api.Bool, settings: Api.WallPaperSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1817860919) + wallpaper.serialize(buffer, true) + unsave.serialize(buffer, true) + settings.serialize(buffer, true) + return (FunctionDescription(name: "account.saveWallPaper", parameters: [("wallpaper", wallpaper), ("unsave", unsave), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func installWallPaper(wallpaper: Api.InputWallPaper, settings: Api.WallPaperSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-18000023) + wallpaper.serialize(buffer, true) + settings.serialize(buffer, true) + return (FunctionDescription(name: "account.installWallPaper", parameters: [("wallpaper", wallpaper), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func resetWallPapers() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1153722364) + + return (FunctionDescription(name: "account.resetWallPapers", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getAutoDownloadSettings() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1457130303) + + return (FunctionDescription(name: "account.getAutoDownloadSettings", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.AutoDownloadSettings? in + let reader = BufferReader(buffer) + var result: Api.account.AutoDownloadSettings? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.AutoDownloadSettings + } + return result + }) + } + + static func saveAutoDownloadSettings(flags: Int32, settings: Api.AutoDownloadSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1995661875) + serializeInt32(flags, buffer: buffer, boxed: false) + settings.serialize(buffer, true) + return (FunctionDescription(name: "account.saveAutoDownloadSettings", parameters: [("flags", flags), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + } + struct langpack { + static func getLangPack(langPack: String, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-219008246) + serializeString(langPack, buffer: buffer, boxed: false) + serializeString(langCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "langpack.getLangPack", parameters: [("langPack", langPack), ("langCode", langCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.LangPackDifference? in + let reader = BufferReader(buffer) + var result: Api.LangPackDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + return result + }) + } + + static func getStrings(langPack: String, langCode: String, keys: [String]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.LangPackString]>) { + let buffer = Buffer() + buffer.appendInt32(-269862909) + serializeString(langPack, buffer: buffer, boxed: false) + serializeString(langCode, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(keys.count)) + for item in keys { + serializeString(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "langpack.getStrings", parameters: [("langPack", langPack), ("langCode", langCode), ("keys", keys)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.LangPackString]? in + let reader = BufferReader(buffer) + var result: [Api.LangPackString]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackString.self) + } + return result + }) + } + + static func getLanguages(langPack: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.LangPackLanguage]>) { + let buffer = Buffer() + buffer.appendInt32(1120311183) + serializeString(langPack, buffer: buffer, boxed: false) + return (FunctionDescription(name: "langpack.getLanguages", parameters: [("langPack", langPack)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.LangPackLanguage]? in + let reader = BufferReader(buffer) + var result: [Api.LangPackLanguage]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackLanguage.self) + } + return result + }) + } + + static func getDifference(langCode: String, fromVersion: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1655576556) + serializeString(langCode, buffer: buffer, boxed: false) + serializeInt32(fromVersion, buffer: buffer, boxed: false) + return (FunctionDescription(name: "langpack.getDifference", parameters: [("langCode", langCode), ("fromVersion", fromVersion)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.LangPackDifference? in + let reader = BufferReader(buffer) + var result: Api.LangPackDifference? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.LangPackDifference + } + return result + }) + } + + static func getLanguage(langPack: String, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1784243458) + serializeString(langPack, buffer: buffer, boxed: false) + serializeString(langCode, buffer: buffer, boxed: false) + return (FunctionDescription(name: "langpack.getLanguage", parameters: [("langPack", langPack), ("langCode", langCode)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.LangPackLanguage? in + let reader = BufferReader(buffer) + var result: Api.LangPackLanguage? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.LangPackLanguage + } + return result + }) + } + } + struct photos { + static func updateProfilePhoto(id: Api.InputPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-256159406) + id.serialize(buffer, true) + return (FunctionDescription(name: "photos.updateProfilePhoto", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UserProfilePhoto? in + let reader = BufferReader(buffer) + var result: Api.UserProfilePhoto? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.UserProfilePhoto + } + return result + }) + } + + static func uploadProfilePhoto(file: Api.InputFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1328726168) + file.serialize(buffer, true) + return (FunctionDescription(name: "photos.uploadProfilePhoto", parameters: [("file", file)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in + let reader = BufferReader(buffer) + var result: Api.photos.Photo? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.photos.Photo + } + return result + }) + } + + static func deletePhotos(id: [Api.InputPhoto]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int64]>) { + let buffer = Buffer() + buffer.appendInt32(-2016444625) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "photos.deletePhotos", parameters: [("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int64]? in + let reader = BufferReader(buffer) + var result: [Int64]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + return result + }) + } + + static func getUserPhotos(userId: Api.InputUser, offset: Int32, maxId: Int64, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1848823128) + userId.serialize(buffer, true) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt64(maxId, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "photos.getUserPhotos", parameters: [("userId", userId), ("offset", offset), ("maxId", maxId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photos? in + let reader = BufferReader(buffer) + var result: Api.photos.Photos? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.photos.Photos + } + return result + }) + } + } + struct phone { + static func getCallConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1430593449) + + return (FunctionDescription(name: "phone.getCallConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.DataJSON? in + let reader = BufferReader(buffer) + var result: Api.DataJSON? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.DataJSON + } + return result + }) + } + + static func acceptCall(peer: Api.InputPhoneCall, gB: Buffer, `protocol`: Api.PhoneCallProtocol) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1003664544) + peer.serialize(buffer, true) + serializeBytes(gB, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + return (FunctionDescription(name: "phone.acceptCall", parameters: [("peer", peer), ("gB", gB), ("`protocol`", `protocol`)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in + let reader = BufferReader(buffer) + var result: Api.phone.PhoneCall? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.phone.PhoneCall + } + return result + }) + } + + static func confirmCall(peer: Api.InputPhoneCall, gA: Buffer, keyFingerprint: Int64, `protocol`: Api.PhoneCallProtocol) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(788404002) + peer.serialize(buffer, true) + serializeBytes(gA, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + return (FunctionDescription(name: "phone.confirmCall", parameters: [("peer", peer), ("gA", gA), ("keyFingerprint", keyFingerprint), ("`protocol`", `protocol`)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in + let reader = BufferReader(buffer) + var result: Api.phone.PhoneCall? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.phone.PhoneCall + } + return result + }) + } + + static func receivedCall(peer: Api.InputPhoneCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(399855457) + peer.serialize(buffer, true) + return (FunctionDescription(name: "phone.receivedCall", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func saveCallDebug(peer: Api.InputPhoneCall, debug: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(662363518) + peer.serialize(buffer, true) + debug.serialize(buffer, true) + return (FunctionDescription(name: "phone.saveCallDebug", parameters: [("peer", peer), ("debug", debug)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func setCallRating(flags: Int32, peer: Api.InputPhoneCall, rating: Int32, comment: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1508562471) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(rating, buffer: buffer, boxed: false) + serializeString(comment, buffer: buffer, boxed: false) + return (FunctionDescription(name: "phone.setCallRating", parameters: [("flags", flags), ("peer", peer), ("rating", rating), ("comment", comment)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + + static func requestCall(flags: Int32, userId: Api.InputUser, randomId: Int32, gAHash: Buffer, `protocol`: Api.PhoneCallProtocol) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1124046573) + serializeInt32(flags, buffer: buffer, boxed: false) + userId.serialize(buffer, true) + serializeInt32(randomId, buffer: buffer, boxed: false) + serializeBytes(gAHash, buffer: buffer, boxed: false) + `protocol`.serialize(buffer, true) + return (FunctionDescription(name: "phone.requestCall", parameters: [("flags", flags), ("userId", userId), ("randomId", randomId), ("gAHash", gAHash), ("`protocol`", `protocol`)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in + let reader = BufferReader(buffer) + var result: Api.phone.PhoneCall? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.phone.PhoneCall + } + return result + }) + } + + static func discardCall(flags: Int32, peer: Api.InputPhoneCall, duration: Int32, reason: Api.PhoneCallDiscardReason, connectionId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1295269440) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(duration, buffer: buffer, boxed: false) + reason.serialize(buffer, true) + serializeInt64(connectionId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "phone.discardCall", parameters: [("flags", flags), ("peer", peer), ("duration", duration), ("reason", reason), ("connectionId", connectionId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift b/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift new file mode 100644 index 0000000000..32572b8d4a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift @@ -0,0 +1,143 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +func imageRepresentationsForApiChatPhoto(_ photo: Api.ChatPhoto) -> [TelegramMediaImageRepresentation] { + var representations: [TelegramMediaImageRepresentation] = [] + switch photo { + case let .chatPhoto(photoSmall, photoBig, dcId): + + let smallResource: TelegramMediaResource + let fullSizeResource: TelegramMediaResource + switch photoSmall { + case let .fileLocationToBeDeprecated(volumeId, localId): + smallResource = CloudPeerPhotoSizeMediaResource(datacenterId: dcId, sizeSpec: .small, volumeId: volumeId, localId: localId) + } + switch photoBig { + case let .fileLocationToBeDeprecated(volumeId, localId): + fullSizeResource = CloudPeerPhotoSizeMediaResource(datacenterId: dcId, sizeSpec: .fullSize, volumeId: volumeId, localId: localId) + } + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: 80.0, height: 80.0), resource: smallResource)) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: 640.0, height: 640.0), resource: fullSizeResource)) + case .chatPhotoEmpty: + break + } + return representations +} + +func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? { + switch chat { + case let .chat(flags, id, title, photo, participantsCount, date, version, migratedTo, adminRights, defaultBannedRights): + let left = (flags & ((1 << 1) | (1 << 2))) != 0 + var migrationReference: TelegramGroupToChannelMigrationReference? + if let migratedTo = migratedTo { + switch migratedTo { + case let .inputChannel(channelId, accessHash): + migrationReference = TelegramGroupToChannelMigrationReference(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), accessHash: accessHash) + case .inputChannelEmpty: + break + } + } + var groupFlags = TelegramGroupFlags() + var role: TelegramGroupRole = .member + if (flags & (1 << 0)) != 0 { + role = .creator + } else if let adminRights = adminRights { + role = .admin(TelegramChatAdminRights(apiAdminRights: adminRights)) + } + if (flags & (1 << 5)) != 0 { + groupFlags.insert(.deactivated) + } + return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: id), title: title, photo: imageRepresentationsForApiChatPhoto(photo), participantCount: Int(participantsCount), role: role, membership: left ? .Left : .Member, flags: groupFlags, defaultBannedRights: defaultBannedRights.flatMap(TelegramChatBannedRights.init(apiBannedRights:)), migrationReference: migrationReference, creationDate: date, version: Int(version)) + case let .chatEmpty(id): + return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: id), title: "", photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0) + case let .chatForbidden(id, title): + return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: id), title: title, photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0) + case let .channel(flags, id, accessHash, title, username, photo, date, version, restrictionReason, adminRights, bannedRights, defaultBannedRights, _/*feed*//*, feedId*/): + let participationStatus: TelegramChannelParticipationStatus + if (flags & Int32(1 << 1)) != 0 { + participationStatus = .kicked + } else if (flags & Int32(1 << 2)) != 0 { + participationStatus = .left + } else { + participationStatus = .member + } + + let info: TelegramChannelInfo + if (flags & Int32(1 << 8)) != 0 { + let infoFlags = TelegramChannelGroupFlags() + info = .group(TelegramChannelGroupInfo(flags: infoFlags)) + } else { + var infoFlags = TelegramChannelBroadcastFlags() + if (flags & Int32(1 << 11)) != 0 { + infoFlags.insert(.messagesShouldHaveSignatures) + } + if (flags & Int32(1 << 20)) != 0 { + infoFlags.insert(.hasDiscussionGroup) + } + info = .broadcast(TelegramChannelBroadcastInfo(flags: infoFlags)) + } + + var channelFlags = TelegramChannelFlags() + if (flags & Int32(1 << 0)) != 0 { + channelFlags.insert(.isCreator) + } + if (flags & Int32(1 << 7)) != 0 { + channelFlags.insert(.isVerified) + } + if (flags & Int32(1 << 19)) != 0 { + channelFlags.insert(.isScam) + } + + let restrictionInfo: PeerAccessRestrictionInfo? + if let restrictionReason = restrictionReason { + restrictionInfo = PeerAccessRestrictionInfo(reason: restrictionReason) + } else { + restrictionInfo = nil + } + + return TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: id), accessHash: accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: date, version: version, participationStatus: participationStatus, info: info, flags: channelFlags, restrictionInfo: restrictionInfo, adminRights: adminRights.flatMap(TelegramChatAdminRights.init), bannedRights: bannedRights.flatMap(TelegramChatBannedRights.init), defaultBannedRights: defaultBannedRights.flatMap(TelegramChatBannedRights.init)) + case let .channelForbidden(flags, id, accessHash, title, untilDate): + let info: TelegramChannelInfo + if (flags & Int32(1 << 8)) != 0 { + info = .group(TelegramChannelGroupInfo(flags: [])) + } else { + info = .broadcast(TelegramChannelBroadcastInfo(flags: [])) + } + + return TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: id), accessHash: accessHash, title: title, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .kicked, info: info, flags: TelegramChannelFlags(), restrictionInfo: nil, adminRights: nil, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: untilDate ?? Int32.max), defaultBannedRights: nil) + } +} + +func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? { + switch rhs { + case .chat, .chatEmpty, .chatForbidden, .channelForbidden: + return parseTelegramGroupOrChannel(chat: rhs) + case let .channel(flags, _, accessHash, title, username, photo, _, _, _, _, _, defaultBannedRights, _/*feed*//*, feedId*/): + if accessHash != nil && (flags & (1 << 12)) == 0 { + return parseTelegramGroupOrChannel(chat: rhs) + } else if let lhs = lhs as? TelegramChannel { + var channelFlags = lhs.flags + if (flags & Int32(1 << 7)) != 0 { + channelFlags.insert(.isVerified) + } else { + let _ = channelFlags.remove(.isVerified) + } + var info = lhs.info + switch info { + case .broadcast: + break + case .group: + let infoFlags = TelegramChannelGroupFlags() + info = .group(TelegramChannelGroupInfo(flags: infoFlags)) + } + return TelegramChannel(id: lhs.id, accessHash: lhs.accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: lhs.creationDate, version: lhs.version, participationStatus: lhs.participationStatus, info: info, flags: channelFlags, restrictionInfo: lhs.restrictionInfo, adminRights: lhs.adminRights, bannedRights: lhs.bannedRights, defaultBannedRights: defaultBannedRights.flatMap(TelegramChatBannedRights.init)) + } else { + return nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ApiUtils.swift b/submodules/TelegramCore/TelegramCore/ApiUtils.swift new file mode 100644 index 0000000000..ccd67db4d0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ApiUtils.swift @@ -0,0 +1,159 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum PeerReference: PostboxCoding, Hashable, Equatable { + case user(id: Int32, accessHash: Int64) + case group(id: Int32) + case channel(id: Int32, accessHash: Int64) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_r", orElse: 0) { + case 0: + self = .user(id: decoder.decodeInt32ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + case 1: + self = .group(id: decoder.decodeInt32ForKey("i", orElse: 0)) + case 2: + self = .channel(id: decoder.decodeInt32ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + default: + assertionFailure() + self = .user(id: 0, accessHash: 0) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .user(id, accessHash): + encoder.encodeInt32(0, forKey: "_r") + encoder.encodeInt32(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + case let .group(id): + encoder.encodeInt32(1, forKey: "_r") + encoder.encodeInt32(id, forKey: "i") + case let .channel(id, accessHash): + encoder.encodeInt32(2, forKey: "_r") + encoder.encodeInt32(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + } + } + + var id: PeerId { + switch self { + case let .user(id, _): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: id) + case let .group(id): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: id) + case let .channel(id, _): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: id) + } + } + + public init?(_ peer: Peer) { + switch peer { + case let user as TelegramUser: + if let accessHash = user.accessHash { + self = .user(id: user.id.id, accessHash: accessHash) + } else { + return nil + } + case let group as TelegramGroup: + self = .group(id: group.id.id) + case let channel as TelegramChannel: + if let accessHash = channel.accessHash { + self = .channel(id: channel.id.id, accessHash: accessHash) + } else { + return nil + } + default: + return nil + } + } + + var inputPeer: Api.InputPeer { + switch self { + case let .user(id, accessHash): + return .inputPeerUser(userId: id, accessHash: accessHash) + case let .group(id): + return .inputPeerChat(chatId: id) + case let .channel(id, accessHash): + return .inputPeerChannel(channelId: id, accessHash: accessHash) + } + } + + var inputUser: Api.InputUser? { + if case let .user(id, accessHash) = self { + return .inputUser(userId: id, accessHash: accessHash) + } else { + return nil + } + } + + var inputChannel: Api.InputChannel? { + if case let .channel(id, accessHash) = self { + return .inputChannel(channelId: id, accessHash: accessHash) + } else { + return nil + } + } +} + +func forceApiInputPeer(_ peer: Peer) -> Api.InputPeer? { + switch peer { + case let user as TelegramUser: + return Api.InputPeer.inputPeerUser(userId: user.id.id, accessHash: user.accessHash ?? 0) + case let group as TelegramGroup: + return Api.InputPeer.inputPeerChat(chatId: group.id.id) + case let channel as TelegramChannel: + if let accessHash = channel.accessHash { + return Api.InputPeer.inputPeerChannel(channelId: channel.id.id, accessHash: accessHash) + } else { + return nil + } + default: + return nil + } +} + +func apiInputPeer(_ peer: Peer) -> Api.InputPeer? { + switch peer { + case let user as TelegramUser where user.accessHash != nil: + return Api.InputPeer.inputPeerUser(userId: user.id.id, accessHash: user.accessHash!) + case let group as TelegramGroup: + return Api.InputPeer.inputPeerChat(chatId: group.id.id) + case let channel as TelegramChannel: + if let accessHash = channel.accessHash { + return Api.InputPeer.inputPeerChannel(channelId: channel.id.id, accessHash: accessHash) + } else { + return nil + } + default: + return nil + } +} + +func apiInputChannel(_ peer: Peer) -> Api.InputChannel? { + if let channel = peer as? TelegramChannel, let accessHash = channel.accessHash { + return Api.InputChannel.inputChannel(channelId: channel.id.id, accessHash: accessHash) + } else { + return nil + } +} + +func apiInputUser(_ peer: Peer) -> Api.InputUser? { + if let user = peer as? TelegramUser, let accessHash = user.accessHash { + return Api.InputUser.inputUser(userId: user.id.id, accessHash: accessHash) + } else { + return nil + } +} + +func apiInputSecretChat(_ peer: Peer) -> Api.InputEncryptedChat? { + if let chat = peer as? TelegramSecretChat { + return Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: chat.accessHash) + } else { + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/AppChangelog.swift b/submodules/TelegramCore/TelegramCore/AppChangelog.swift new file mode 100644 index 0000000000..434d83c1e4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AppChangelog.swift @@ -0,0 +1,51 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedAppChangelog(postbox: Postbox, network: Network, stateManager: AccountStateManager, appVersion: String) -> Signal { + return stateManager.pollStateUpdateCompletion() + |> take(1) + |> mapToSignal { _ -> Signal in + return postbox.transaction { transaction -> AppChangelogState in + return transaction.getPreferencesEntry(key: PreferencesKeys.appChangelogState) as? AppChangelogState ?? AppChangelogState.default + } + |> mapToSignal { appChangelogState -> Signal in + let appChangelogState = appChangelogState + if appChangelogState.checkedVersion == appVersion { + return .complete() + } + let previousVersion = appChangelogState.previousVersion + return network.request(Api.functions.help.getAppChangelog(prevAppVersion: previousVersion)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + + return postbox.transaction { transaction in + updateAppChangelogState(transaction: transaction, { state in + var state = state + state.checkedVersion = appVersion + state.previousVersion = appVersion + return state + }) + } + } + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/AppChangelogState.swift b/submodules/TelegramCore/TelegramCore/AppChangelogState.swift new file mode 100644 index 0000000000..e87208d983 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AppChangelogState.swift @@ -0,0 +1,50 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +struct AppChangelogState: PreferencesEntry, Equatable { + var checkedVersion: String + var previousVersion: String + + static var `default` = AppChangelogState(checkedVersion: "", previousVersion: "5.0.8") + + init(checkedVersion: String, previousVersion: String) { + self.checkedVersion = checkedVersion + self.previousVersion = previousVersion + } + + init(decoder: PostboxDecoder) { + self.checkedVersion = decoder.decodeStringForKey("checkedVersion", orElse: "") + self.previousVersion = decoder.decodeStringForKey("previousVersion", orElse: "") + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.checkedVersion, forKey: "checkedVersion") + encoder.encodeString(self.previousVersion, forKey: "previousVersion") + } + + func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? AppChangelogState else { + return false + } + + return self == to + } +} + +func updateAppChangelogState(transaction: Transaction, _ f: @escaping (AppChangelogState) -> AppChangelogState) { + transaction.updatePreferencesEntry(key: PreferencesKeys.appChangelogState, { current in + return f((current as? AppChangelogState) ?? AppChangelogState.default) + }) +} diff --git a/submodules/TelegramCore/TelegramCore/AppConfiguration.swift b/submodules/TelegramCore/TelegramCore/AppConfiguration.swift new file mode 100644 index 0000000000..2719561a11 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AppConfiguration.swift @@ -0,0 +1,53 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct AppConfiguration: PreferencesEntry, Equatable { + public var data: JSON? + + public static var defaultValue: AppConfiguration { + return AppConfiguration(data: nil) + } + + init(data: JSON?) { + self.data = data + } + + public init(decoder: PostboxDecoder) { + self.data = decoder.decodeObjectForKey("data", decoder: { JSON(decoder: $0) }) as? JSON + } + + public func encode(_ encoder: PostboxEncoder) { + if let data = self.data { + encoder.encodeObject(data, forKey: "data") + } else { + encoder.encodeNil(forKey: "data") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? AppConfiguration else { + return false + } + return self == to + } +} + +public func currentAppConfiguration(transaction: Transaction) -> AppConfiguration { + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration { + return entry + } else { + return AppConfiguration.defaultValue + } +} + +func updateAppConfiguration(transaction: Transaction, _ f: (AppConfiguration) -> AppConfiguration) { + let current = currentAppConfiguration(transaction: transaction) + let updated = f(current) + if updated != current { + transaction.setPreferencesEntry(key: PreferencesKeys.appConfiguration, value: updated) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ApplyMaxReadIndexInteractively.swift b/submodules/TelegramCore/TelegramCore/ApplyMaxReadIndexInteractively.swift new file mode 100644 index 0000000000..c1adcea2d1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ApplyMaxReadIndexInteractively.swift @@ -0,0 +1,166 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func applyMaxReadIndexInteractively(postbox: Postbox, stateManager: AccountStateManager, index: MessageIndex) -> Signal { + return postbox.transaction { transaction -> Void in + applyMaxReadIndexInteractively(transaction: transaction, stateManager: stateManager, index: index) + } +} + +func applyMaxReadIndexInteractively(transaction: Transaction, stateManager: AccountStateManager, index: MessageIndex) { + let messageIds = transaction.applyInteractiveReadMaxIndex(index) + if index.id.peerId.namespace == Namespaces.Peer.SecretChat { + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + for id in messageIds { + if let message = transaction.getMessage(id) { + for attribute in message.attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + let updatedAttributes = currentMessage.attributes.map({ currentAttribute -> MessageAttribute in + if let currentAttribute = currentAttribute as? AutoremoveTimeoutMessageAttribute { + return AutoremoveTimeoutMessageAttribute(timeout: currentAttribute.timeout, countdownBeginTime: timestamp) + } else { + return currentAttribute + } + }) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + transaction.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: id) + } + break + } + } + } + } + } else if index.id.peerId.namespace == Namespaces.Peer.CloudUser || index.id.peerId.namespace == Namespaces.Peer.CloudGroup || index.id.peerId.namespace == Namespaces.Peer.CloudChannel { + stateManager.notifyAppliedIncomingReadMessages([index.id]) + } +} + +func applyOutgoingReadMaxIndex(transaction: Transaction, index: MessageIndex, beginCountdownAt timestamp: Int32) { + let messageIds = transaction.applyOutgoingReadMaxIndex(index) + if index.id.peerId.namespace == Namespaces.Peer.SecretChat { + for id in messageIds { + applySecretOutgoingMessageReadActions(transaction: transaction, id: id, beginCountdownAt: timestamp) + } + } +} + +func maybeReadSecretOutgoingMessage(transaction: Transaction, index: MessageIndex) { + guard index.id.peerId.namespace == Namespaces.Peer.SecretChat else { + assertionFailure() + return + } + guard index.id.namespace == Namespaces.Message.Local else { + assertionFailure() + return + } + + guard let combinedState = transaction.getCombinedPeerReadState(index.id.peerId) else { + return + } + + if combinedState.isOutgoingMessageIndexRead(index) { + applySecretOutgoingMessageReadActions(transaction: transaction, id: index.id, beginCountdownAt: index.timestamp) + } +} + +func applySecretOutgoingMessageReadActions(transaction: Transaction, id: MessageId, beginCountdownAt timestamp: Int32) { + guard id.peerId.namespace == Namespaces.Peer.SecretChat else { + assertionFailure() + return + } + guard id.namespace == Namespaces.Message.Local else { + assertionFailure() + return + } + + if let message = transaction.getMessage(id), !message.flags.contains(.Incoming) { + if message.flags.intersection([.Unsent, .Sending, .Failed]).isEmpty { + for attribute in message.attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && !message.containsSecretMedia { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + let updatedAttributes = currentMessage.attributes.map({ currentAttribute -> MessageAttribute in + if let currentAttribute = currentAttribute as? AutoremoveTimeoutMessageAttribute { + return AutoremoveTimeoutMessageAttribute(timeout: currentAttribute.timeout, countdownBeginTime: timestamp) + } else { + return currentAttribute + } + }) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + transaction.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: id) + } + break + } + } + } + } +} + +public func togglePeerUnreadMarkInteractively(postbox: Postbox, viewTracker: AccountViewTracker, peerId: PeerId, setToValue: Bool? = nil) -> Signal { + return postbox.transaction { transaction -> Void in + togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: viewTracker, peerId: peerId, setToValue: setToValue) + } +} + +public func togglePeerUnreadMarkInteractively(transaction: Transaction, viewTracker: AccountViewTracker, peerId: PeerId, setToValue: Bool? = nil) { + let namespace: MessageId.Namespace + if peerId.namespace == Namespaces.Peer.SecretChat { + namespace = Namespaces.Message.SecretIncoming + } else { + namespace = Namespaces.Message.Cloud + } + if let states = transaction.getPeerReadStates(peerId) { + for i in 0 ..< states.count { + if states[i].0 == namespace { + if states[i].1.isUnread { + if setToValue == nil || !(setToValue!) { + if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: namespace) { + let _ = transaction.applyInteractiveReadMaxIndex(index) + } else { + transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: false, interactive: true) + } + viewTracker.updateMarkAllMentionsSeen(peerId: peerId) + } + } else if namespace == Namespaces.Message.Cloud || namespace == Namespaces.Message.SecretIncoming { + if setToValue == nil || setToValue! { + transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: true, interactive: true) + } + } + } + } + } +} + +public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Void in + if peerId.namespace == Namespaces.Peer.SecretChat { + return + } + account.viewTracker.updateMarkAllMentionsSeen(peerId: peerId) + } + |> ignoreValues +} + +public func markAllChatsAsReadInteractively(transaction: Transaction, viewTracker: AccountViewTracker, groupId: PeerGroupId) { + for peerId in transaction.getUnreadChatListPeerIds(groupId: groupId) { + togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: viewTracker, peerId: peerId, setToValue: false) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift b/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift new file mode 100644 index 0000000000..ff9ca5dcc7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift @@ -0,0 +1,299 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit + import UIKit +#endif + +func applyMediaResourceChanges(from: Media, to: Media, postbox: Postbox) { + if let fromImage = from as? TelegramMediaImage, let toImage = to as? TelegramMediaImage { + let fromSmallestRepresentation = smallestImageRepresentation(fromImage.representations) + if let fromSmallestRepresentation = fromSmallestRepresentation, let toSmallestRepresentation = smallestImageRepresentation(toImage.representations) { + let leeway: CGFloat = 4.0 + let widthDifference = fromSmallestRepresentation.dimensions.width - toSmallestRepresentation.dimensions.width + let heightDifference = fromSmallestRepresentation.dimensions.height - toSmallestRepresentation.dimensions.height + if abs(widthDifference) < leeway && abs(heightDifference) < leeway { + postbox.mediaBox.moveResourceData(from: fromSmallestRepresentation.resource.id, to: toSmallestRepresentation.resource.id) + } + } + if let fromLargestRepresentation = largestImageRepresentation(fromImage.representations), let toLargestRepresentation = largestImageRepresentation(toImage.representations) { + postbox.mediaBox.moveResourceData(from: fromLargestRepresentation.resource.id, to: toLargestRepresentation.resource.id) + } + } else if let fromFile = from as? TelegramMediaFile, let toFile = to as? TelegramMediaFile { + if let fromPreview = smallestImageRepresentation(fromFile.previewRepresentations), let toPreview = smallestImageRepresentation(toFile.previewRepresentations) { + postbox.mediaBox.moveResourceData(from: fromPreview.resource.id, to: toPreview.resource.id) + } + if (fromFile.size == toFile.size || fromFile.resource.size == toFile.resource.size) && fromFile.mimeType == toFile.mimeType { + postbox.mediaBox.moveResourceData(from: fromFile.resource.id, to: toFile.resource.id) + } + } +} + +func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, message: Message, result: Api.Updates) -> Signal { + return postbox.transaction { transaction -> Void in + let messageId: Int32? + var apiMessage: Api.Message? + + for resultMessage in result.messages { + if let id = resultMessage.id { + if id.peerId == message.id.peerId { + apiMessage = resultMessage + break + } + } + } + + if let apiMessage = apiMessage, let id = apiMessage.id { + messageId = id.id + } else { + messageId = result.rawMessageIds.first + } + + var updatedTimestamp: Int32? + if let apiMessage = apiMessage { + switch apiMessage { + case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _): + updatedTimestamp = date + case .messageEmpty: + break + case let .messageService(_, _, _, _, _, date, _): + updatedTimestamp = date + } + } else { + switch result { + case let .updateShortSentMessage(_, _, _, _, date, _, _): + updatedTimestamp = date + default: + break + } + } + + let channelPts = result.channelPts + + var sentStickers: [TelegramMediaFile] = [] + var sentGifs: [TelegramMediaFile] = [] + + if let updatedTimestamp = updatedTimestamp { + transaction.offsetPendingMessagesTimestamps(lowerBound: message.id, excludeIds: Set([message.id]), timestamp: updatedTimestamp) + } + + transaction.updateMessage(message.id, update: { currentMessage in + let updatedId: MessageId + if let messageId = messageId { + updatedId = MessageId(peerId: currentMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: messageId) + } else { + updatedId = currentMessage.id + } + + let media: [Media] + var attributes: [MessageAttribute] + let text: String + let forwardInfo: StoreMessageForwardInfo? + if let apiMessage = apiMessage, let updatedMessage = StoreMessage(apiMessage: apiMessage) { + media = updatedMessage.media + attributes = updatedMessage.attributes + text = updatedMessage.text + forwardInfo = updatedMessage.forwardInfo + } else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities) = result { + let (mediaValue, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId) + if let mediaValue = mediaValue { + media = [mediaValue] + } else { + media = [] + } + + var updatedAttributes: [MessageAttribute] = currentMessage.attributes + if let entities = entities, !entities.isEmpty { + for i in 0 ..< updatedAttributes.count { + if updatedAttributes[i] is TextEntitiesMessageAttribute { + updatedAttributes.remove(at: i) + break + } + } + updatedAttributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities))) + } + + attributes = updatedAttributes + text = currentMessage.text + + forwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init) + } else { + media = currentMessage.media + attributes = currentMessage.attributes + text = currentMessage.text + forwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init) + } + + if let channelPts = channelPts { + for i in 0 ..< attributes.count { + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + break + } + } + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + } + + if let fromMedia = currentMessage.media.first, let toMedia = media.first { + applyMediaResourceChanges(from: fromMedia, to: toMedia, postbox: postbox) + } + + if forwardInfo == nil { + for media in media { + if let file = media as? TelegramMediaFile { + if file.isSticker { + sentStickers.append(file) + } else if file.isVideo && file.isAnimated { + sentGifs.append(file) + } + } + } + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + break + } + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: attributes, media: media, textEntities: entitiesAttribute?.entities) + + return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, groupingKey: currentMessage.groupingKey, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: forwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)) + }) + for file in sentStickers { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + } + for file in sentGifs { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + } + stateManager.addUpdates(result) + } +} + +func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManager, messages: [Message], result: Api.Updates) -> Signal { + guard !messages.isEmpty else { + return .complete() + } + + return postbox.transaction { transaction -> Void in + let updatedRawMessageIds = result.updatedRawMessageIds + + var resultMessages: [MessageId: StoreMessage] = [:] + for apiMessage in result.messages { + if let resultMessage = StoreMessage(apiMessage: apiMessage), case let .Id(id) = resultMessage.id { + resultMessages[id] = resultMessage + } + } + + var mapping: [(Message, MessageIndex, StoreMessage)] = [] + + for message in messages { + var uniqueId: Int64? + inner: for attribute in message.attributes { + if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute { + uniqueId = outgoingInfo.uniqueId + break inner + } + } + if let uniqueId = uniqueId { + if let updatedId = updatedRawMessageIds[uniqueId] { + if let storeMessage = resultMessages[MessageId(peerId: message.id.peerId, namespace: Namespaces.Message.Cloud, id: updatedId)], case let .Id(id) = storeMessage.id { + mapping.append((message, MessageIndex(id: id, timestamp: storeMessage.timestamp), storeMessage)) + } + } else { + assertionFailure() + } + } else { + assertionFailure() + } + } + + mapping.sort { $0.1 < $1.1 } + + let latestPreviousId = mapping.map({ $0.0.id }).max() + + var sentStickers: [TelegramMediaFile] = [] + var sentGifs: [TelegramMediaFile] = [] + + var updatedGroupingKey: Int64? + for (_, _, updatedMessage) in mapping { + if let updatedGroupingKey = updatedGroupingKey { + assert(updatedGroupingKey == updatedMessage.groupingKey) + } + updatedGroupingKey = updatedMessage.groupingKey + } + + if let latestPreviousId = latestPreviousId, let latestIndex = mapping.last?.1 { + transaction.offsetPendingMessagesTimestamps(lowerBound: latestPreviousId, excludeIds: Set(mapping.map { $0.0.id }), timestamp: latestIndex.timestamp) + } + + if let updatedGroupingKey = updatedGroupingKey { + transaction.updateMessageGroupingKeysAtomically(mapping.map { $0.0.id }, groupingKey: updatedGroupingKey) + } + + for (message, _, updatedMessage) in mapping { + transaction.updateMessage(message.id, update: { currentMessage in + let updatedId: MessageId + if case let .Id(id) = updatedMessage.id { + updatedId = id + } else { + updatedId = currentMessage.id + } + + let media: [Media] + let attributes: [MessageAttribute] + let text: String + + media = updatedMessage.media + attributes = updatedMessage.attributes + text = updatedMessage.text + + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + + if let fromMedia = currentMessage.media.first, let toMedia = media.first { + applyMediaResourceChanges(from: fromMedia, to: toMedia, postbox: postbox) + } + + if storeForwardInfo == nil { + for media in media { + if let file = media as? TelegramMediaFile { + if file.isSticker { + sentStickers.append(file) + } else if file.isVideo && file.isAnimated { + sentGifs.append(file) + } + } + } + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + break + } + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: attributes, media: media, textEntities: entitiesAttribute?.entities) + + return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, groupingKey: currentMessage.groupingKey, timestamp: updatedMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)) + }) + } + + for file in sentStickers { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + } + for file in sentGifs { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + } + stateManager.addUpdates(result) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ArchivedStickerPacks.swift b/submodules/TelegramCore/TelegramCore/ArchivedStickerPacks.swift new file mode 100644 index 0000000000..499f7d9a16 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ArchivedStickerPacks.swift @@ -0,0 +1,54 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum ArchivedStickerPacksNamespace: Int32 { + case stickers = 0 + case masks = 1 +} + +public final class ArchivedStickerPackItem { + public let info: StickerPackCollectionInfo + public let topItems: [StickerPackItem] + + public init(info: StickerPackCollectionInfo, topItems: [StickerPackItem]) { + self.info = info + self.topItems = topItems + } +} + +public func archivedStickerPacks(account: Account, namespace: ArchivedStickerPacksNamespace = .stickers) -> Signal<[ArchivedStickerPackItem], NoError> { + var flags: Int32 = 0 + if case .masks = namespace { + flags |= 1 << 0 + } + return account.network.request(Api.functions.messages.getArchivedStickers(flags: flags, offsetId: 0, limit: 100)) + |> map { result -> [ArchivedStickerPackItem] in + var archivedItems: [ArchivedStickerPackItem] = [] + switch result { + case let .archivedStickers(_, sets): + for set in sets { + let (info, items) = parsePreviewStickerSet(set) + archivedItems.append(ArchivedStickerPackItem(info: info, topItems: items)) + } + } + return archivedItems + } |> `catch` { _ in + return .single([]) + } +} + +public func removeArchivedStickerPack(account: Account, info: StickerPackCollectionInfo) -> Signal { + return account.network.request(Api.functions.messages.uninstallStickerSet(stickerset: Api.InputStickerSet.inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ArchivedStickerPacksInfo.swift b/submodules/TelegramCore/TelegramCore/ArchivedStickerPacksInfo.swift new file mode 100644 index 0000000000..bc3160252a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ArchivedStickerPacksInfo.swift @@ -0,0 +1,42 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct ArchivedStickerPacksInfoId { + public let rawValue: MemoryBuffer + public let id: Int32 + + init(_ rawValue: MemoryBuffer) { + self.rawValue = rawValue + assert(rawValue.length == 4) + var idValue: Int32 = 0 + memcpy(&idValue, rawValue.memory, 4) + self.id = idValue + } + + init(_ id: Int32) { + self.id = id + var idValue: Int32 = id + self.rawValue = MemoryBuffer(memory: malloc(4)!, capacity: 4, length: 4, freeWhenDone: true) + memcpy(self.rawValue.memory, &idValue, 4) + } +} + +public final class ArchivedStickerPacksInfo: OrderedItemListEntryContents { + public let count: Int32 + + init(count: Int32) { + self.count = count + } + + public init(decoder: PostboxDecoder) { + self.count = decoder.decodeInt32ForKey("c", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.count, forKey: "c") + } +} diff --git a/submodules/TelegramCore/TelegramCore/AuthorSignatureMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/AuthorSignatureMessageAttribute.swift new file mode 100644 index 0000000000..66d0a2e67f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AuthorSignatureMessageAttribute.swift @@ -0,0 +1,24 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class AuthorSignatureMessageAttribute: MessageAttribute { + public let signature: String + + public let associatedPeerIds: [PeerId] = [] + + init(signature: String) { + self.signature = signature + } + + required public init(decoder: PostboxDecoder) { + self.signature = decoder.decodeStringForKey("s", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.signature, forKey: "s") + } +} diff --git a/submodules/TelegramCore/TelegramCore/Authorization.swift b/submodules/TelegramCore/TelegramCore/Authorization.swift new file mode 100644 index 0000000000..6da3fbfcae --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Authorization.swift @@ -0,0 +1,533 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum AuthorizationCodeRequestError { + case invalidPhoneNumber + case limitExceeded + case generic(info: (Int, String)?) + case phoneLimitExceeded + case phoneBanned + case timeout +} + +private func switchToAuthorizedAccount(transaction: AccountManagerModifier, account: UnauthorizedAccount) { + let nextSortOrder = (transaction.getRecords().map({ record -> Int32 in + for attribute in record.attributes { + if let attribute = attribute as? AccountSortOrderAttribute { + return attribute.order + } + } + return 0 + }).max() ?? 0) + 1 + transaction.updateRecord(account.id, { _ in + return AccountRecord(id: account.id, attributes: [AccountEnvironmentAttribute(environment: account.testingEnvironment ? .test : .production), AccountSortOrderAttribute(order: nextSortOrder)], temporarySessionId: nil) + }) + transaction.setCurrentId(account.id) + transaction.removeAuth() +} + +public func sendAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, syncContacts: Bool) -> Signal { + let sendCode = Api.functions.auth.sendCode(flags: 0, phoneNumber: phoneNumber, currentNumber: nil, apiId: apiId, apiHash: apiHash) + + let codeAndAccount = account.network.request(sendCode, automaticFloodWait: false) + |> map { result in + return (result, account) + } + |> `catch` { error -> Signal<(Api.auth.SentCode, UnauthorizedAccount), MTRpcError> in + switch (error.errorDescription ?? "") { + case Regex("(PHONE_|USER_|NETWORK_)MIGRATE_(\\d+)"): + let range = error.errorDescription.range(of: "MIGRATE_")! + let updatedMasterDatacenterId = Int32(error.errorDescription[range.upperBound ..< error.errorDescription.endIndex])! + let updatedAccount = account.changedMasterDatacenterId(accountManager: accountManager, masterDatacenterId: updatedMasterDatacenterId) + return updatedAccount + |> mapToSignalPromotingError { updatedAccount -> Signal<(Api.auth.SentCode, UnauthorizedAccount), MTRpcError> in + return updatedAccount.network.request(sendCode, automaticFloodWait: false) + |> map { sentCode in + return (sentCode, updatedAccount) + } + } + case _: + return .fail(error) + } + } + |> mapError { error -> AuthorizationCodeRequestError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_NUMBER_INVALID" { + return .invalidPhoneNumber + } else if error.errorDescription == "PHONE_NUMBER_FLOOD" { + return .phoneLimitExceeded + } else if error.errorDescription == "PHONE_NUMBER_BANNED" { + return .phoneBanned + } else { + return .generic(info: (Int(error.errorCode), error.errorDescription)) + } + } + |> timeout(20.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.timeout)) + + return codeAndAccount + |> mapToSignal { (sentCode, account) -> Signal in + return account.postbox.transaction { transaction -> UnauthorizedAccount in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, termsOfService): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + var explicitTerms = false + if let termsOfService = termsOfService { + switch termsOfService { + case let .termsOfService(value): + if (value.flags & (1 << 0)) != 0 { + explicitTerms = true + } + } + } + + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, termsOfService: termsOfService.flatMap(UnauthorizedAccountTermsOfService.init(apiTermsOfService:)).flatMap({ ($0, explicitTerms) }), syncContacts: syncContacts))) + } + return account + } + |> mapError { _ -> AuthorizationCodeRequestError in + return .generic(info: nil) + } + } +} + +public func resendAuthorizationCode(account: UnauthorizedAccount) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let state = transaction.getState() as? UnauthorizedAccountState { + switch state.contents { + case let .confirmationCodeEntry(number, _, hash, _, nextType, _, syncContacts): + if nextType != nil { + return account.network.request(Api.functions.auth.resendCode(phoneNumber: number, phoneCodeHash: hash), automaticFloodWait: false) + |> mapError { error -> AuthorizationCodeRequestError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_NUMBER_INVALID" { + return .invalidPhoneNumber + } else if error.errorDescription == "PHONE_NUMBER_FLOOD" { + return .phoneLimitExceeded + } else if error.errorDescription == "PHONE_NUMBER_BANNED" { + return .phoneBanned + } else { + return .generic(info: (Int(error.errorCode), error.errorDescription)) + } + } + |> mapToSignal { sentCode -> Signal in + return account.postbox.transaction { transaction -> Void in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, termsOfService): + + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + + var explicitTerms = false + if let termsOfService = termsOfService { + switch termsOfService { + case let .termsOfService(value): + if (value.flags & (1 << 0)) != 0 { + explicitTerms = true + } + } + } + + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, termsOfService: termsOfService.flatMap(UnauthorizedAccountTermsOfService.init(apiTermsOfService:)).flatMap({ ($0, explicitTerms) }), syncContacts: syncContacts))) + + } + } |> mapError { _ -> AuthorizationCodeRequestError in return .generic(info: nil) } + } + } else { + return .fail(.generic(info: nil)) + } + default: + return .complete() + } + } else { + return .fail(.generic(info: nil)) + } + } + |> mapError { _ -> AuthorizationCodeRequestError in + return .generic(info: nil) + } + |> switchToLatest +} + +public enum AuthorizationCodeVerificationError { + case invalidCode + case limitExceeded + case generic + case codeExpired +} + +private enum AuthorizationCodeResult { + case authorization(Api.auth.Authorization) + case password(hint: String) + case signUp +} + +public struct AuthorizationSignUpData { + let number: String + let codeHash: String + let code: String + let termsOfService: UnauthorizedAccountTermsOfService? + let syncContacts: Bool +} + +public enum AuthorizeWithCodeResult { + case signUp(AuthorizationSignUpData) + case loggedIn +} + +public func authorizeWithCode(accountManager: AccountManager, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let state = transaction.getState() as? UnauthorizedAccountState { + switch state.contents { + case let .confirmationCodeEntry(number, _, hash, _, _, _, syncContacts): + return account.network.request(Api.functions.auth.signIn(phoneNumber: number, phoneCodeHash: hash, phoneCode: code), automaticFloodWait: false) + |> map { authorization in + return .authorization(authorization) + } + |> `catch` { error -> Signal in + switch (error.errorCode, error.errorDescription ?? "") { + case (401, "SESSION_PASSWORD_NEEDED"): + return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) + |> mapError { error -> AuthorizationCodeVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else { + return .generic + } + } + |> mapToSignal { result -> Signal in + switch result { + case let .password(password): + return .single(.password(hint: password.hint ?? "")) + } + } + case let (_, errorDescription): + if errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if errorDescription == "PHONE_CODE_INVALID" { + return .fail(.invalidCode) + } else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" { + return .fail(.codeExpired) + } else if errorDescription == "PHONE_NUMBER_UNOCCUPIED" { + return .single(.signUp) + } else { + return .fail(.generic) + } + } + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Signal in + switch result { + case .signUp: + return .single(.signUp(AuthorizationSignUpData(number: number, codeHash: hash, code: code, termsOfService: termsOfService, syncContacts: syncContacts))) + case let .password(hint): + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint, number: number, code: code, suggestReset: false, syncContacts: syncContacts))) + return .single(.loggedIn) + case let .authorization(authorization): + switch authorization { + case let .authorization(_, _, user): + let user = TelegramUser(user: user) + let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) + initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) + transaction.setState(state) + } + return accountManager.transaction { transaction -> AuthorizeWithCodeResult in + switchToAuthorizedAccount(transaction: transaction, account: account) + return .loggedIn + } + } + } + |> switchToLatest + |> mapError { _ -> AuthorizationCodeVerificationError in + return .generic + } + } + default: + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> AuthorizationCodeVerificationError in + return .generic + } + |> switchToLatest +} + +public func beginSignUp(account: UnauthorizedAccount, data: AuthorizationSignUpData) -> Signal { + return account.postbox.transaction { transaction -> Void in + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .signUp(number: data.number, codeHash: data.codeHash, code: data.code, firstName: "", lastName: "", termsOfService: data.termsOfService, syncContacts: data.syncContacts))) + } + |> ignoreValues +} + +public enum AuthorizationPasswordVerificationError { + case limitExceeded + case invalidPassword + case generic +} + +public func authorizeWithPassword(accountManager: AccountManager, account: UnauthorizedAccount, password: String, syncContacts: Bool) -> Signal { + return verifyPassword(account, password: password) + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .fail(.invalidPassword) + } else { + return .fail(.generic) + } + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Signal in + switch result { + case let .authorization(_, _, user): + let user = TelegramUser(user: user) + let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) + /*transaction.updatePeersInternal([user], update: { current, peer -> Peer? in + return peer + })*/ + initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) + transaction.setState(state) + + return accountManager.transaction { transaction -> Void in + switchToAuthorizedAccount(transaction: transaction, account: account) + } + } + } + |> switchToLatest + |> mapError { _ -> AuthorizationPasswordVerificationError in + return .generic + } + } +} + +public enum PasswordRecoveryRequestError { + case limitExceeded + case generic +} + +public enum PasswordRecoveryOption { + case none + case email(pattern: String) +} + +public func requestPasswordRecovery(account: UnauthorizedAccount) -> Signal { + return account.network.request(Api.functions.auth.requestPasswordRecovery()) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if error.errorDescription.hasPrefix("PASSWORD_RECOVERY_NA") { + return .single(nil) + } else { + return .fail(.generic) + } + } + |> map { result -> PasswordRecoveryOption in + if let result = result { + switch result { + case let .passwordRecovery(emailPattern): + return .email(pattern: emailPattern) + } + } else { + return .none + } + } +} + +public enum PasswordRecoveryError { + case invalidCode + case limitExceeded + case expired +} + +public func performPasswordRecovery(accountManager: AccountManager, account: UnauthorizedAccount, code: String, syncContacts: Bool) -> Signal { + return account.network.request(Api.functions.auth.recoverPassword(code: code)) + |> mapError { error -> PasswordRecoveryError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription.hasPrefix("PASSWORD_RECOVERY_EXPIRED") { + return .expired + } else { + return .invalidCode + } + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Signal in + switch result { + case let .authorization(_, _, user): + let user = TelegramUser(user: user) + let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) + /*transaction.updatePeersInternal([user], update: { current, peer -> Peer? in + return peer + })*/ + initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) + transaction.setState(state) + return accountManager.transaction { transaction -> Void in + switchToAuthorizedAccount(transaction: transaction, account: account) + } + } + } + |> switchToLatest + |> mapError { _ in return PasswordRecoveryError.expired } + } +} + +public enum AccountResetError { + case generic + case limitExceeded +} + +public func performAccountReset(account: UnauthorizedAccount) -> Signal { + return account.network.request(Api.functions.account.deleteAccount(reason: "")) + |> map { _ -> Int32? in return nil } + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("2FA_CONFIRM_WAIT_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "2FA_CONFIRM_WAIT_".count)...]) + if let value = Int32(timeout) { + return .single(value) + } else { + return .fail(.generic) + } + } else if error.errorDescription == "2FA_RECENT_CONFIRM" { + return .fail(.limitExceeded) + } else { + return .fail(.generic) + } + } + |> mapToSignal { timeout -> Signal in + return account.postbox.transaction { transaction -> Void in + guard let state = transaction.getState() as? UnauthorizedAccountState else { + return + } + var number: String? + var syncContacts: Bool? + if case let .passwordEntry(_, numberValue, _, _, syncContactsValue) = state.contents { + number = numberValue + syncContacts = syncContactsValue + } else if case let .awaitingAccountReset(_, numberValue, syncContactsValue) = state.contents { + number = numberValue + syncContacts = syncContactsValue + } + if let number = number, let syncContacts = syncContacts { + if let timeout = timeout { + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: state.isTestingEnvironment, masterDatacenterId: state.masterDatacenterId, contents: .awaitingAccountReset(protectedUntil: timestamp + timeout, number: number, syncContacts: syncContacts))) + } else { + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: state.isTestingEnvironment, masterDatacenterId: state.masterDatacenterId, contents: .empty)) + } + } + } + |> mapError { _ in return AccountResetError.generic } + } +} + +public enum SignUpError { + case generic + case limitExceeded + case codeExpired + case invalidFirstName + case invalidLastName +} + +public func signUpWithName(accountManager: AccountManager, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let state = transaction.getState() as? UnauthorizedAccountState, case let .signUp(number, codeHash, code, _, _, _, syncContacts) = state.contents { + return account.network.request(Api.functions.auth.signUp(phoneNumber: number, phoneCodeHash: codeHash, phoneCode: code, firstName: firstName, lastName: lastName)) + |> mapError { error -> SignUpError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_CODE_EXPIRED" { + return .codeExpired + } else if error.errorDescription == "FIRSTNAME_INVALID" { + return .invalidFirstName + } else if error.errorDescription == "LASTNAME_INVALID" { + return .invalidLastName + } else { + return .generic + } + } + |> mapToSignal { result -> Signal in + switch result { + case let .authorization(_, _, user): + let user = TelegramUser(user: user) + let appliedState = account.postbox.transaction { transaction -> Void in + let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) + if let hole = account.postbox.seedConfiguration.initializeChatListWithHole.topLevel { + transaction.replaceChatListHole(groupId: .root, index: hole.index, hole: nil) + } + initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) + transaction.setState(state) + } + |> introduceError(SignUpError.self) + + let switchedAccounts = accountManager.transaction { transaction -> Void in + switchToAuthorizedAccount(transaction: transaction, account: account) + } + |> introduceError(SignUpError.self) + + if let avatarData = avatarData { + let resource = LocalFileMediaResource(fileId: arc4random64()) + account.postbox.mediaBox.storeResourceData(resource.id, data: avatarData) + + return updatePeerPhotoInternal(postbox: account.postbox, network: account.network, stateManager: nil, accountPeerId: user.id, peer: .single(user), photo: uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: resource), mapResourceToAvatarSizes: { _, _ in .single([:]) }) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { result -> Signal in + switch result { + case .complete: + return .complete() + case .progress: + return .never() + } + } + |> then(appliedState) + |> then(switchedAccounts) + } else { + return appliedState + |> then(switchedAccounts) + } + } + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> SignUpError in + return .generic + } + |> switchToLatest +} + +public enum AuthorizationStateReset { + case empty +} + +public func resetAuthorizationState(account: UnauthorizedAccount, to value: AuthorizationStateReset) -> Signal { + return account.postbox.transaction { transaction -> Void in + if let state = transaction.getState() as? UnauthorizedAccountState { + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: state.isTestingEnvironment, masterDatacenterId: state.masterDatacenterId, contents: .empty)) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/AutodownloadSettings.swift b/submodules/TelegramCore/TelegramCore/AutodownloadSettings.swift new file mode 100644 index 0000000000..82ad5a98eb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AutodownloadSettings.swift @@ -0,0 +1,139 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum AutodownloadPreset { + case low + case medium + case high +} + +public struct AutodownloadPresetSettings: PostboxCoding, Equatable { + public let disabled: Bool + public let photoSizeMax: Int32 + public let videoSizeMax: Int32 + public let fileSizeMax: Int32 + public let preloadLargeVideo: Bool + public let lessDataForPhoneCalls: Bool + + public init(disabled: Bool, photoSizeMax: Int32, videoSizeMax: Int32, fileSizeMax: Int32, preloadLargeVideo: Bool, lessDataForPhoneCalls: Bool) { + self.disabled = disabled + self.photoSizeMax = photoSizeMax + self.videoSizeMax = videoSizeMax + self.fileSizeMax = fileSizeMax + self.preloadLargeVideo = preloadLargeVideo + self.lessDataForPhoneCalls = lessDataForPhoneCalls + } + + public init(decoder: PostboxDecoder) { + self.disabled = decoder.decodeInt32ForKey("disabled", orElse: 0) != 0 + self.photoSizeMax = decoder.decodeInt32ForKey("photoSizeMax", orElse: 0) + self.videoSizeMax = decoder.decodeInt32ForKey("videoSizeMax", orElse: 0) + self.fileSizeMax = decoder.decodeInt32ForKey("fileSizeMax", orElse: 0) + self.preloadLargeVideo = decoder.decodeInt32ForKey("preloadLargeVideo", orElse: 0) != 0 + self.lessDataForPhoneCalls = decoder.decodeInt32ForKey("lessDataForPhoneCalls", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.disabled ? 1 : 0, forKey: "disabled") + encoder.encodeInt32(self.photoSizeMax, forKey: "photoSizeMax") + encoder.encodeInt32(self.videoSizeMax, forKey: "videoSizeMax") + encoder.encodeInt32(self.fileSizeMax, forKey: "fileSizeMax") + encoder.encodeInt32(self.preloadLargeVideo ? 1 : 0, forKey: "preloadLargeVideo") + encoder.encodeInt32(self.lessDataForPhoneCalls ? 1 : 0, forKey: "lessDataForPhoneCalls") + } +} + +public struct AutodownloadSettings: PreferencesEntry, Equatable { + public let lowPreset: AutodownloadPresetSettings + public let mediumPreset: AutodownloadPresetSettings + public let highPreset: AutodownloadPresetSettings + + public static var defaultSettings: AutodownloadSettings { + return AutodownloadSettings(lowPreset: AutodownloadPresetSettings(disabled: false, photoSizeMax: 1 * 1024 * 1024, videoSizeMax: 0, fileSizeMax: 0, preloadLargeVideo: false, lessDataForPhoneCalls: true), + mediumPreset: AutodownloadPresetSettings(disabled: false, photoSizeMax: 1 * 1024 * 1024, videoSizeMax: Int32(2.5 * 1024 * 1024), fileSizeMax: 1 * 1024 * 1024, preloadLargeVideo: false, lessDataForPhoneCalls: false), + highPreset: AutodownloadPresetSettings(disabled: false, photoSizeMax: 1 * 1024 * 1024, videoSizeMax: 10 * 1024 * 1024, fileSizeMax: 3 * 1024 * 1024, preloadLargeVideo: false, lessDataForPhoneCalls: false)) + } + + init(lowPreset: AutodownloadPresetSettings, mediumPreset: AutodownloadPresetSettings, highPreset: AutodownloadPresetSettings) { + self.lowPreset = lowPreset + self.mediumPreset = mediumPreset + self.highPreset = highPreset + } + + public init(decoder: PostboxDecoder) { + self.lowPreset = decoder.decodeObjectForKey("lowPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings + self.mediumPreset = decoder.decodeObjectForKey("mediumPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings + self.highPreset = decoder.decodeObjectForKey("highPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.lowPreset, forKey: "lowPreset") + encoder.encodeObject(self.mediumPreset, forKey: "mediumPreset") + encoder.encodeObject(self.highPreset, forKey: "highPreset") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? AutodownloadSettings { + return self == to + } else { + return false + } + } + + public static func ==(lhs: AutodownloadSettings, rhs: AutodownloadSettings) -> Bool { + return lhs.lowPreset == rhs.lowPreset && lhs.mediumPreset == rhs.mediumPreset && lhs.highPreset == rhs.highPreset + } +} + +public func updateAutodownloadSettingsInteractively(accountManager: AccountManager, _ f: @escaping (AutodownloadSettings) -> AutodownloadSettings) -> Signal { + return accountManager.transaction { transaction -> Void in + transaction.updateSharedData(SharedDataKeys.autodownloadSettings, { entry in + let currentSettings: AutodownloadSettings + if let entry = entry as? AutodownloadSettings { + currentSettings = entry + } else { + currentSettings = AutodownloadSettings.defaultSettings + } + return f(currentSettings) + }) + } +} + +extension AutodownloadPresetSettings { + init(apiAutodownloadSettings: Api.AutoDownloadSettings) { + switch apiAutodownloadSettings { + case let .autoDownloadSettings(flags, photoSizeMax, videoSizeMax, fileSizeMax): + self.init(disabled: (flags & (1 << 0)) != 0, photoSizeMax: photoSizeMax, videoSizeMax: videoSizeMax, fileSizeMax: fileSizeMax, preloadLargeVideo: (flags & (1 << 1)) != 0, lessDataForPhoneCalls: (flags & (1 << 3)) != 0) + } + } +} + +extension AutodownloadSettings { + init(apiAutodownloadSettings: Api.account.AutoDownloadSettings) { + switch apiAutodownloadSettings { + case let .autoDownloadSettings(low, medium, high): + self.init(lowPreset: AutodownloadPresetSettings(apiAutodownloadSettings: low), mediumPreset: AutodownloadPresetSettings(apiAutodownloadSettings: medium), highPreset: AutodownloadPresetSettings(apiAutodownloadSettings: high)) + } + } +} + +func apiAutodownloadPresetSettings(_ autodownloadPresetSettings: AutodownloadPresetSettings) -> Api.AutoDownloadSettings { + var flags: Int32 = 0 + if autodownloadPresetSettings.disabled { + flags |= (1 << 0) + } + if autodownloadPresetSettings.preloadLargeVideo { + flags |= (1 << 1) + } + if autodownloadPresetSettings.lessDataForPhoneCalls { + flags |= (1 << 3) + } + return .autoDownloadSettings(flags: flags, photoSizeMax: autodownloadPresetSettings.photoSizeMax, videoSizeMax: autodownloadPresetSettings.videoSizeMax, fileSizeMax: autodownloadPresetSettings.fileSizeMax) +} + diff --git a/submodules/TelegramCore/TelegramCore/AutoremoveTimeoutMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/AutoremoveTimeoutMessageAttribute.swift new file mode 100644 index 0000000000..bca58df927 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AutoremoveTimeoutMessageAttribute.swift @@ -0,0 +1,74 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public class AutoremoveTimeoutMessageAttribute: MessageAttribute { + public let timeout: Int32 + public let countdownBeginTime: Int32? + + public var associatedMessageIds: [MessageId] = [] + + public init(timeout: Int32, countdownBeginTime: Int32?) { + self.timeout = timeout + self.countdownBeginTime = countdownBeginTime + } + + required public init(decoder: PostboxDecoder) { + self.timeout = decoder.decodeInt32ForKey("t", orElse: 0) + self.countdownBeginTime = decoder.decodeOptionalInt32ForKey("c") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.timeout, forKey: "t") + if let countdownBeginTime = self.countdownBeginTime { + encoder.encodeInt32(countdownBeginTime, forKey: "c") + } else { + encoder.encodeNil(forKey: "c") + } + } +} + +public extension Message { + public var containsSecretMedia: Bool { + var found = false + for attribute in self.attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + if attribute.timeout > 1 * 60 { + return false + } + found = true + break + } + } + + if !found { + return false + } + + for media in self.media { + switch media { + case _ as TelegramMediaImage: + return true + case let file as TelegramMediaFile: + if file.isVideo || file.isAnimated || file.isVoice { + return true + } + default: + break + } + } + + return false + } +} diff --git a/submodules/TelegramCore/TelegramCore/BlockedPeers.swift b/submodules/TelegramCore/TelegramCore/BlockedPeers.swift new file mode 100644 index 0000000000..1b5f352f98 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/BlockedPeers.swift @@ -0,0 +1,76 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func requestBlockedPeers(account: Account) -> Signal<[Peer], NoError> { + return account.network.request(Api.functions.contacts.getBlocked(offset: 0, limit: 100)) + |> retryRequest + |> mapToSignal { result -> Signal<[Peer], NoError> in + return account.postbox.transaction { transaction -> [Peer] in + var peers: [Peer] = [] + let apiUsers: [Api.User] + switch result { + case let .blocked(_, users): + apiUsers = users + case let .blockedSlice(_, _, users): + apiUsers = users + } + for user in apiUsers { + let parsed = TelegramUser(user: user) + peers.append(parsed) + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + + return peers + } + } +} + +public func requestUpdatePeerIsBlocked(account: Account, peerId: PeerId, isBlocked: Bool) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + let signal: Signal + if isBlocked { + signal = account.network.request(Api.functions.contacts.block(id: inputUser)) + } else { + signal = account.network.request(Api.functions.contacts.unblock(id: inputUser)) + } + return signal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if result != nil { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + return previous.withUpdatedIsBlocked(isBlocked) + }) + } + } + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/BlockedPeersContext.swift b/submodules/TelegramCore/TelegramCore/BlockedPeersContext.swift new file mode 100644 index 0000000000..e5027dd32d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/BlockedPeersContext.swift @@ -0,0 +1,237 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct BlockedPeersContextState: Equatable { + public var isLoadingMore: Bool + public var canLoadMore: Bool + public var totalCount: Int? + public var peers: [RenderedPeer] +} + +public enum BlockedPeersContextAddError { + case generic +} + +public enum BlockedPeersContextRemoveError { + case generic +} + +public final class BlockedPeersContext { + private let account: Account + private var _state: BlockedPeersContextState { + didSet { + if self._state != oldValue { + self._statePromise.set(.single(self._state)) + } + } + } + private let _statePromise = Promise() + public var state: Signal { + return self._statePromise.get() + } + + private let disposable = MetaDisposable() + + public init(account: Account) { + assert(Queue.mainQueue().isCurrent()) + + self.account = account + self._state = BlockedPeersContextState(isLoadingMore: false, canLoadMore: true, totalCount: nil, peers: []) + self._statePromise.set(.single(self._state)) + + self.loadMore() + } + + deinit { + assert(Queue.mainQueue().isCurrent()) + self.disposable.dispose() + } + + public func loadMore() { + assert(Queue.mainQueue().isCurrent()) + + if self._state.isLoadingMore || !self._state.canLoadMore { + return + } + self._state = BlockedPeersContextState(isLoadingMore: true, canLoadMore: self._state.canLoadMore, totalCount: self._state.totalCount, peers: self._state.peers) + let postbox = self.account.postbox + self.disposable.set((self.account.network.request(Api.functions.contacts.getBlocked(offset: Int32(self._state.peers.count), limit: 64)) + |> retryRequest + |> mapToSignal { result -> Signal<(peers: [RenderedPeer], canLoadMore: Bool, totalCount: Int?), NoError> in + return postbox.transaction { transaction -> (peers: [RenderedPeer], canLoadMore: Bool, totalCount: Int?) in + switch result { + case let .blocked(blocked, users): + var peers: [Peer] = [] + for user in users { + peers.append(TelegramUser(user: user)) + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in updated }) + + var renderedPeers: [RenderedPeer] = [] + for blockedPeer in blocked { + switch blockedPeer { + case let .contactBlocked(userId, _): + if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) { + renderedPeers.append(RenderedPeer(peer: peer)) + } + } + } + + return (renderedPeers, false, nil) + case let .blockedSlice(count, blocked, users): + var peers: [Peer] = [] + for user in users { + peers.append(TelegramUser(user: user)) + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in updated }) + + var renderedPeers: [RenderedPeer] = [] + for blockedPeer in blocked { + switch blockedPeer { + case let .contactBlocked(userId, _): + if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) { + renderedPeers.append(RenderedPeer(peer: peer)) + } + } + } + + return (renderedPeers, true, Int(count)) + } + } + } + |> deliverOnMainQueue).start(next: { [weak self] (peers, canLoadMore, totalCount) in + guard let strongSelf = self else { + return + } + + var mergedPeers = strongSelf._state.peers + var existingPeerIds = Set(mergedPeers.map { $0.peerId }) + for peer in peers { + if !existingPeerIds.contains(peer.peerId) { + existingPeerIds.insert(peer.peerId) + mergedPeers.append(peer) + } + } + + let updatedTotalCount: Int? + if !canLoadMore { + updatedTotalCount = mergedPeers.count + } else if let totalCount = totalCount { + updatedTotalCount = totalCount + } else { + updatedTotalCount = strongSelf._state.totalCount + } + + strongSelf._state = BlockedPeersContextState(isLoadingMore: false, canLoadMore: canLoadMore, totalCount: updatedTotalCount, peers: mergedPeers) + })) + } + + public func add(peerId: PeerId) -> Signal { + assert(Queue.mainQueue().isCurrent()) + + let postbox = self.account.postbox + let network = self.account.network + return self.account.postbox.transaction { transaction -> Api.InputUser? in + return transaction.getPeer(peerId).flatMap(apiInputUser) + } + |> introduceError(BlockedPeersContextAddError.self) + |> mapToSignal { [weak self] inputUser -> Signal in + guard let inputUser = inputUser else { + return .fail(.generic) + } + return network.request(Api.functions.contacts.block(id: inputUser)) + |> mapError { _ -> BlockedPeersContextAddError in + return .generic + } + |> mapToSignal { _ -> Signal in + return postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> introduceError(BlockedPeersContextAddError.self) + } + |> deliverOnMainQueue + |> mapToSignal { peer -> Signal in + guard let strongSelf = self, let peer = peer else { + return .complete() + } + + var mergedPeers = strongSelf._state.peers + let existingPeerIds = Set(mergedPeers.map { $0.peerId }) + if !existingPeerIds.contains(peer.id) { + mergedPeers.insert(RenderedPeer(peer: peer), at: 0) + } + + let updatedTotalCount: Int? + if let totalCount = strongSelf._state.totalCount { + updatedTotalCount = totalCount + 1 + } else { + updatedTotalCount = nil + } + + strongSelf._state = BlockedPeersContextState(isLoadingMore: strongSelf._state.isLoadingMore, canLoadMore: strongSelf._state.canLoadMore, totalCount: updatedTotalCount, peers: mergedPeers) + return .complete() + } + } + } + + public func remove(peerId: PeerId) -> Signal { + assert(Queue.mainQueue().isCurrent()) + + let network = self.account.network + return self.account.postbox.transaction { transaction -> Api.InputUser? in + return transaction.getPeer(peerId).flatMap(apiInputUser) + } + |> introduceError(BlockedPeersContextRemoveError.self) + |> mapToSignal { [weak self] inputUser -> Signal in + guard let inputUser = inputUser else { + return .fail(.generic) + } + return network.request(Api.functions.contacts.unblock(id: inputUser)) + |> mapError { _ -> BlockedPeersContextRemoveError in + return .generic + } + |> deliverOnMainQueue + |> mapToSignal { _ -> Signal in + guard let strongSelf = self else { + return .complete() + } + + var mergedPeers = strongSelf._state.peers + var found = false + for i in 0 ..< mergedPeers.count { + if mergedPeers[i].peerId == peerId { + found = true + mergedPeers.remove(at: i) + break + } + } + + let updatedTotalCount: Int? + if let totalCount = strongSelf._state.totalCount { + if found { + updatedTotalCount = totalCount - 1 + } else { + updatedTotalCount = totalCount + } + } else { + updatedTotalCount = nil + } + + strongSelf._state = BlockedPeersContextState(isLoadingMore: strongSelf._state.isLoadingMore, canLoadMore: strongSelf._state.canLoadMore, totalCount: updatedTotalCount, peers: mergedPeers) + return .complete() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/BotInfo.swift b/submodules/TelegramCore/TelegramCore/BotInfo.swift new file mode 100644 index 0000000000..549de05bdd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/BotInfo.swift @@ -0,0 +1,68 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct BotCommand: PostboxCoding, Equatable { + public let text: String + public let description: String + + init(text: String, description: String) { + self.text = text + self.description = description + } + + public init(decoder: PostboxDecoder) { + self.text = decoder.decodeStringForKey("t", orElse: "") + self.description = decoder.decodeStringForKey("d", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.text, forKey: "t") + encoder.encodeString(self.description, forKey: "d") + } + + public static func ==(lhs: BotCommand, rhs: BotCommand) -> Bool { + return lhs.text == rhs.text && lhs.description == rhs.description + } +} + +public final class BotInfo: PostboxCoding, Equatable { + public let description: String + public let commands: [BotCommand] + + init(description: String, commands: [BotCommand]) { + self.description = description + self.commands = commands + } + + public init(decoder: PostboxDecoder) { + self.description = decoder.decodeStringForKey("d", orElse: "") + self.commands = decoder.decodeObjectArrayWithDecoderForKey("c") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.description, forKey: "d") + encoder.encodeObjectArray(self.commands, forKey: "c") + } + + public static func ==(lhs: BotInfo, rhs: BotInfo) -> Bool { + return lhs.description == rhs.description && lhs.commands == rhs.commands + } +} + +extension BotInfo { + convenience init(apiBotInfo: Api.BotInfo) { + switch apiBotInfo { + case let .botInfo(_, description, commands): + self.init(description: description, commands: commands.map { command in + switch command { + case let .botCommand(command, description): + return BotCommand(text: command, description: description) + } + }) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/BotPaymentForm.swift b/submodules/TelegramCore/TelegramCore/BotPaymentForm.swift new file mode 100644 index 0000000000..152a316285 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/BotPaymentForm.swift @@ -0,0 +1,438 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public struct BotPaymentInvoiceFields: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let name = BotPaymentInvoiceFields(rawValue: 1 << 0) + public static let phone = BotPaymentInvoiceFields(rawValue: 1 << 1) + public static let email = BotPaymentInvoiceFields(rawValue: 1 << 2) + public static let shippingAddress = BotPaymentInvoiceFields(rawValue: 1 << 3) + public static let flexibleShipping = BotPaymentInvoiceFields(rawValue: 1 << 4) +} + +public struct BotPaymentPrice { + public let label: String + public let amount: Int64 + + public init(label: String, amount: Int64) { + self.label = label + self.amount = amount + } +} + +public struct BotPaymentInvoice { + public let isTest: Bool + public let requestedFields: BotPaymentInvoiceFields + public let currency: String + public let prices: [BotPaymentPrice] +} + +public struct BotPaymentNativeProvider { + public let name: String + public let params: String +} + +public struct BotPaymentShippingAddress: Equatable { + public let streetLine1: String + public let streetLine2: String + public let city: String + public let state: String + public let countryIso2: String + public let postCode: String + + public init(streetLine1: String, streetLine2: String, city: String, state: String, countryIso2: String, postCode: String) { + self.streetLine1 = streetLine1 + self.streetLine2 = streetLine2 + self.city = city + self.state = state + self.countryIso2 = countryIso2 + self.postCode = postCode + } + + public static func ==(lhs: BotPaymentShippingAddress, rhs: BotPaymentShippingAddress) -> Bool { + if lhs.streetLine1 != rhs.streetLine1 { + return false + } + if lhs.streetLine2 != rhs.streetLine2 { + return false + } + if lhs.city != rhs.city { + return false + } + if lhs.state != rhs.state { + return false + } + if lhs.countryIso2 != rhs.countryIso2 { + return false + } + if lhs.postCode != rhs.postCode { + return false + } + return true + } +} + +public struct BotPaymentRequestedInfo: Equatable { + public let name: String? + public let phone: String? + public let email: String? + public let shippingAddress: BotPaymentShippingAddress? + + public init(name: String?, phone: String?, email: String?, shippingAddress: BotPaymentShippingAddress?) { + self.name = name + self.phone = phone + self.email = email + self.shippingAddress = shippingAddress + } + + public static func ==(lhs: BotPaymentRequestedInfo, rhs: BotPaymentRequestedInfo) -> Bool { + if lhs.name != rhs.name { + return false + } + if lhs.phone != rhs.phone { + return false + } + if lhs.email != rhs.email { + return false + } + if lhs.shippingAddress != rhs.shippingAddress { + return false + } + return true + } +} + +public enum BotPaymentSavedCredentials: Equatable { + case card(id: String, title: String) + + public static func ==(lhs: BotPaymentSavedCredentials, rhs: BotPaymentSavedCredentials) -> Bool { + switch lhs { + case let .card(id, title): + if case .card(id, title) = rhs { + return true + } else { + return false + } + } + } +} + +public struct BotPaymentForm { + public let canSaveCredentials: Bool + public let passwordMissing: Bool + public let invoice: BotPaymentInvoice + public let providerId: PeerId + public let url: String + public let nativeProvider: BotPaymentNativeProvider? + public let savedInfo: BotPaymentRequestedInfo? + public let savedCredentials: BotPaymentSavedCredentials? +} + +public enum BotPaymentFormRequestError { + case generic +} + +extension BotPaymentInvoice { + init(apiInvoice: Api.Invoice) { + switch apiInvoice { + case let .invoice(flags, currency, prices): + var fields = BotPaymentInvoiceFields() + if (flags & (1 << 1)) != 0 { + fields.insert(.name) + } + if (flags & (1 << 2)) != 0 { + fields.insert(.phone) + } + if (flags & (1 << 3)) != 0 { + fields.insert(.email) + } + if (flags & (1 << 4)) != 0 { + fields.insert(.shippingAddress) + } + if (flags & (1 << 5)) != 0 { + fields.insert(.flexibleShipping) + } + self.init(isTest: (flags & (1 << 0)) != 0, requestedFields: fields, currency: currency, prices: prices.map { + switch $0 { + case let .labeledPrice(label, amount): + return BotPaymentPrice(label: label, amount: amount) + } + }) + } + } +} + +extension BotPaymentRequestedInfo { + init(apiInfo: Api.PaymentRequestedInfo) { + switch apiInfo { + case let .paymentRequestedInfo(_, name, phone, email, shippingAddress): + var parsedShippingAddress: BotPaymentShippingAddress? + if let shippingAddress = shippingAddress { + switch shippingAddress { + case let .postAddress(streetLine1, streetLine2, city, state, countryIso2, postCode): + parsedShippingAddress = BotPaymentShippingAddress(streetLine1: streetLine1, streetLine2: streetLine2, city: city, state: state, countryIso2: countryIso2, postCode: postCode) + } + } + self.init(name: name, phone: phone, email: email, shippingAddress: parsedShippingAddress) + } + } +} + +public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: MessageId) -> Signal { + return network.request(Api.functions.payments.getPaymentForm(msgId: messageId.id)) + |> `catch` { _ -> Signal in + return .fail(.generic) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> BotPaymentForm in + switch result { + case let .paymentForm(flags, _, invoice, providerId, url, nativeProvider, nativeParams, savedInfo, savedCredentials, apiUsers): + var peers: [Peer] = [] + for user in apiUsers { + let parsed = TelegramUser(user: user) + peers.append(parsed) + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + + let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice) + var parsedNativeProvider: BotPaymentNativeProvider? + if let nativeProvider = nativeProvider, let nativeParams = nativeParams { + switch nativeParams { + case let .dataJSON(data): + parsedNativeProvider = BotPaymentNativeProvider(name: nativeProvider, params: data) + } + } + let parsedSavedInfo = savedInfo.flatMap(BotPaymentRequestedInfo.init) + var parsedSavedCredentials: BotPaymentSavedCredentials? + if let savedCredentials = savedCredentials { + switch savedCredentials { + case let .paymentSavedCredentialsCard(id, title): + parsedSavedCredentials = .card(id: id, title: title) + } + } + return BotPaymentForm(canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: providerId), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials) + } + } |> mapError { _ -> BotPaymentFormRequestError in return .generic } + } +} + +public enum ValidateBotPaymentFormError { + case generic + case shippingNotAvailable + case addressStateInvalid + case addressPostcodeInvalid + case addressCityInvalid + case nameInvalid + case emailInvalid + case phoneInvalid +} + +public struct BotPaymentShippingOption { + public let id: String + public let title: String + public let prices: [BotPaymentPrice] +} + +public struct BotPaymentValidatedFormInfo { + public let id: String? + public let shippingOptions: [BotPaymentShippingOption]? +} + +extension BotPaymentShippingOption { + init(apiOption: Api.ShippingOption) { + switch apiOption { + case let .shippingOption(id, title, prices): + self.init(id: id, title: title, prices: prices.map { + switch $0 { + case let .labeledPrice(label, amount): + return BotPaymentPrice(label: label, amount: amount) + } + }) + } + } +} + +public func validateBotPaymentForm(network: Network, saveInfo: Bool, messageId: MessageId, formInfo: BotPaymentRequestedInfo) -> Signal { + var flags: Int32 = 0 + if saveInfo { + flags |= (1 << 0) + } + var infoFlags: Int32 = 0 + if let _ = formInfo.name { + infoFlags |= (1 << 0) + } + if let _ = formInfo.phone { + infoFlags |= (1 << 1) + } + if let _ = formInfo.email { + infoFlags |= (1 << 2) + } + var apiShippingAddress: Api.PostAddress? + if let address = formInfo.shippingAddress { + infoFlags |= (1 << 3) + apiShippingAddress = .postAddress(streetLine1: address.streetLine1, streetLine2: address.streetLine2, city: address.city, state: address.state, countryIso2: address.countryIso2, postCode: address.postCode) + } + return network.request(Api.functions.payments.validateRequestedInfo(flags: flags, msgId: messageId.id, info: .paymentRequestedInfo(flags: infoFlags, name: formInfo.name, phone: formInfo.phone, email: formInfo.email, shippingAddress: apiShippingAddress))) + |> mapError { error -> ValidateBotPaymentFormError in + if error.errorDescription == "SHIPPING_NOT_AVAILABLE" { + return .shippingNotAvailable + } else if error.errorDescription == "ADDRESS_STATE_INVALID" { + return .addressStateInvalid + } else if error.errorDescription == "ADDRESS_POSTCODE_INVALID" { + return .addressPostcodeInvalid + } else if error.errorDescription == "ADDRESS_CITY_INVALID" { + return .addressCityInvalid + } else if error.errorDescription == "REQ_INFO_NAME_INVALID" { + return .nameInvalid + } else if error.errorDescription == "REQ_INFO_EMAIL_INVALID" { + return .emailInvalid + } else if error.errorDescription == "REQ_INFO_PHONE_INVALID" { + return .phoneInvalid + } else { + return .generic + } + } + |> map { result -> BotPaymentValidatedFormInfo in + switch result { + case let .validatedRequestedInfo(_, id, shippingOptions): + return BotPaymentValidatedFormInfo(id: id, shippingOptions: shippingOptions.flatMap { + return $0.map(BotPaymentShippingOption.init) + }) + } + } +} + +public enum BotPaymentCredentials { + case generic(data: String, saveOnServer: Bool) + case saved(id: String, tempPassword: Data) + case applePay(data: String) +} + +public enum SendBotPaymentFormError { + case generic + case precheckoutFailed + case paymentFailed + case alreadyPaid +} + +public enum SendBotPaymentResult { + case done + case externalVerificationRequired(url: String) +} + +public func sendBotPaymentForm(account: Account, messageId: MessageId, validatedInfoId: String?, shippingOptionId: String?, credentials: BotPaymentCredentials) -> Signal { + let apiCredentials: Api.InputPaymentCredentials + switch credentials { + case let .generic(data, saveOnServer): + var credentialsFlags: Int32 = 0 + if saveOnServer { + credentialsFlags |= (1 << 0) + } + apiCredentials = .inputPaymentCredentials(flags: credentialsFlags, data: .dataJSON(data: data)) + case let .saved(id, tempPassword): + apiCredentials = .inputPaymentCredentialsSaved(id: id, tmpPassword: Buffer(data: tempPassword)) + case let .applePay(data): + apiCredentials = .inputPaymentCredentialsApplePay(paymentData: .dataJSON(data: data)) + } + var flags: Int32 = 0 + if validatedInfoId != nil { + flags |= (1 << 0) + } + if shippingOptionId != nil { + flags |= (1 << 1) + } + return account.network.request(Api.functions.payments.sendPaymentForm(flags: flags, msgId: messageId.id, requestedInfoId: validatedInfoId, shippingOptionId: shippingOptionId, credentials: apiCredentials)) + |> map { result -> SendBotPaymentResult in + switch result { + case let .paymentResult(updates): + account.stateManager.addUpdates(updates) + return .done + case let .paymentVerficationNeeded(url): + return .externalVerificationRequired(url: url) + } + } + |> `catch` { error -> Signal in + if error.errorDescription == "BOT_PRECHECKOUT_FAILED" { + return .fail(.precheckoutFailed) + } else if error.errorDescription == "PAYMENT_FAILED" { + return .fail(.paymentFailed) + } else if error.errorDescription == "INVOICE_ALREADY_PAID" { + return .fail(.alreadyPaid) + } + return .fail(.generic) + } +} + +public struct BotPaymentReceipt { + public let invoice: BotPaymentInvoice + public let info: BotPaymentRequestedInfo? + public let shippingOption: BotPaymentShippingOption? + public let credentialsTitle: String +} + +public func requestBotPaymentReceipt(network: Network, messageId: MessageId) -> Signal { + return network.request(Api.functions.payments.getPaymentReceipt(msgId: messageId.id)) + |> retryRequest + |> map { result -> BotPaymentReceipt in + switch result { + case let .paymentReceipt(_, _, _, invoice, _, info, shipping, _, _, credentialsTitle, _): + let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice) + let parsedInfo = info.flatMap(BotPaymentRequestedInfo.init) + let shippingOption = shipping.flatMap(BotPaymentShippingOption.init) + return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle) + } + } +} + +public struct BotPaymentInfo: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let paymentInfo = BotPaymentInfo(rawValue: 1 << 0) + public static let shippingInfo = BotPaymentInfo(rawValue: 1 << 1) +} + +public func clearBotPaymentInfo(network: Network, info: BotPaymentInfo) -> Signal { + var flags: Int32 = 0 + if info.contains(.paymentInfo) { + flags |= (1 << 0) + } + if info.contains(.shippingInfo) { + flags |= (1 << 1) + } + return network.request(Api.functions.payments.clearSavedInfo(flags: flags)) + |> retryRequest + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/Buffer.swift b/submodules/TelegramCore/TelegramCore/Buffer.swift new file mode 100644 index 0000000000..6c0b384819 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Buffer.swift @@ -0,0 +1,358 @@ +import Foundation + +public struct Int128 { + public var _0: Int64 + public var _1: Int64 +} + +public struct Int256 { + public var _0: Int64 + public var _1: Int64 + public var _2: Int64 + public var _3: Int64 +} + +func serializeInt32(_ value: Int32, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(-1471112230) + } + buffer.appendInt32(value) +} + +func serializeInt64(_ value: Int64, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(570911930) + } + buffer.appendInt64(value) +} + +func serializeDouble(_ value: Double, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(571523412) + } + buffer.appendDouble(value) +} + +func serializeString(_ value: String, buffer: Buffer, boxed: Bool) { + let stringBuffer = Buffer() + let data = value.data(using: .utf8, allowLossyConversion: true) ?? Data() + data.withUnsafeBytes { bytes in + stringBuffer.appendBytes(bytes, length: UInt(data.count)) + } + serializeBytes(stringBuffer, buffer: buffer, boxed: boxed) +} + +func serializeBytes(_ value: Buffer, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(-1255641564) + } + + var length: Int32 = Int32(value.size) + var padding: Int32 = 0 + if (length >= 254) + { + var tmp: UInt8 = 254 + buffer.appendBytes(&tmp, length: 1) + buffer.appendBytes(&length, length: 3) + padding = (((length % 4) == 0 ? length : (length + 4 - (length % 4)))) - length; + } + else + { + buffer.appendBytes(&length, length: 1) + + let e1 = (((length + 1) % 4) == 0 ? (length + 1) : ((length + 1) + 4 - ((length + 1) % 4))) + padding = (e1) - (length + 1) + } + + if value.size != 0 { + buffer.appendBytes(value.data!, length: UInt(length)) + } + + var i: Int32 = 0 + var tmp: UInt8 = 0 + while i < padding { + buffer.appendBytes(&tmp, length: 1) + i += 1 + } +} + +func serializeInt128(_ value: Int128, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(1270167083) + } + + buffer.appendInt64(value._0) + buffer.appendInt64(value._1) +} + +func serializeInt256(_ value: Int256, buffer: Buffer, boxed: Bool) { + if boxed { + buffer.appendInt32(153731887) + } + + buffer.appendInt64(value._0) + buffer.appendInt64(value._1) + buffer.appendInt64(value._2) + buffer.appendInt64(value._3) +} + +func parseInt128(_ reader: BufferReader) -> Int128? { + let _0 = reader.readInt64() + let _1 = reader.readInt64() + if _0 != nil && _1 != nil { + return Int128(_0: _0!, _1: _1!) + } + return nil +} + +func parseInt256(_ reader: BufferReader) -> Int256? { + let _0 = reader.readInt64() + let _1 = reader.readInt64() + let _2 = reader.readInt64() + let _3 = reader.readInt64() + if _0 != nil && _1 != nil && _2 != nil && _3 != nil { + return Int256(_0: _0!, _1: _1!, _2: _2!, _3: _3!) + } + return nil +} + +private func roundUp(_ numToRound: Int, multiple: Int) -> Int +{ + if multiple == 0 { + return numToRound + } + + let remainder = numToRound % multiple + if remainder == 0 { + return numToRound; + } + + return numToRound + multiple - remainder +} + +func parseBytes(_ reader: BufferReader) -> Buffer? { + if let tmp = reader.readBytesAsInt32(1) { + var paddingBytes: Int = 0 + var length: Int = 0 + if tmp == 254 { + if let len = reader.readBytesAsInt32(3) { + length = Int(len) + paddingBytes = roundUp(length, multiple: 4) - length + } + else { + return nil + } + } + else { + length = Int(tmp) + paddingBytes = roundUp(length + 1, multiple: 4) - (length + 1) + } + + let buffer = reader.readBuffer(length) + reader.skip(paddingBytes) + return buffer + } + return nil +} + +func parseString(_ reader: BufferReader) -> String? { + if let buffer = parseBytes(reader) { + return (NSString(data: buffer.makeData() as Data, encoding: String.Encoding.utf8.rawValue) as? String) ?? "" + } + return nil +} + +public class Buffer: CustomStringConvertible { + var data: UnsafeMutableRawPointer? + var _size: UInt = 0 + private var capacity: UInt = 0 + private let freeWhenDone: Bool + + public var size: Int { + return Int(self._size) + } + + deinit { + if self.freeWhenDone { + free(self.data) + } + } + + public init(memory: UnsafeMutableRawPointer?, size: Int, capacity: Int, freeWhenDone: Bool) { + self.data = memory + self._size = UInt(size) + self.capacity = UInt(capacity) + self.freeWhenDone = freeWhenDone + } + + public init() { + self.data = nil + self._size = 0 + self.capacity = 0 + self.freeWhenDone = true + } + + convenience public init(data: Data?) { + self.init() + + if let data = data { + data.withUnsafeBytes { bytes in + self.appendBytes(bytes, length: UInt(data.count)) + } + } + } + + + + public func makeData() -> Data { + return self.withUnsafeMutablePointer { pointer, size -> Data in + if let pointer = pointer { + return Data(bytes: pointer.assumingMemoryBound(to: UInt8.self), count: Int(size)) + } else { + return Data() + } + } + } + + public var description: String { + get { + var string = "" + if let data = self.data { + var i: UInt = 0 + let bytes = data.assumingMemoryBound(to: UInt8.self) + while i < _size && i < 8 { + string += String(format: "%02x", Int(bytes.advanced(by: Int(i)).pointee)) + i += 1 + } + if i < _size { + string += "...\(_size)b" + } + } else { + string += "" + } + return string + } + } + + public func appendBytes(_ bytes: UnsafeRawPointer, length: UInt) { + if self.capacity < self._size + length { + self.capacity = self._size + length + 128 + if self.data == nil { + self.data = malloc(Int(self.capacity))! + } + else { + self.data = realloc(self.data, Int(self.capacity))! + } + } + + memcpy(self.data?.advanced(by: Int(self._size)), bytes, Int(length)) + self._size += length + } + + public func appendBuffer(_ buffer: Buffer) { + if self.capacity < self._size + buffer._size { + self.capacity = self._size + buffer._size + 128 + if self.data == nil { + self.data = malloc(Int(self.capacity))! + } + else { + self.data = realloc(self.data, Int(self.capacity))! + } + } + + memcpy(self.data?.advanced(by: Int(self._size)), buffer.data, Int(buffer._size)) + } + + public func appendInt32(_ value: Int32) { + var v = value + self.appendBytes(&v, length: 4) + } + + public func appendInt64(_ value: Int64) { + var v = value + self.appendBytes(&v, length: 8) + } + + public func appendDouble(_ value: Double) { + var v = value + self.appendBytes(&v, length: 8) + } + + public func withUnsafeMutablePointer(_ f: (UnsafeMutableRawPointer?, UInt) -> R) -> R { + return f(self.data, self._size) + } +} + +public class BufferReader { + private let buffer: Buffer + public private(set) var offset: UInt = 0 + + public init(_ buffer: Buffer) { + self.buffer = buffer + } + + public func reset() { + self.offset = 0 + } + + public func skip(_ count: Int) { + self.offset = min(self.buffer._size, self.offset + UInt(count)) + } + + public func readInt32() -> Int32? { + if self.offset + 4 <= self.buffer._size { + let value: Int32 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int32.self).pointee + self.offset += 4 + return value + } + return nil + } + + public func readInt64() -> Int64? { + if self.offset + 8 <= self.buffer._size { + let value: Int64 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int64.self).pointee + self.offset += 8 + return value + } + return nil + } + + public func readDouble() -> Double? { + if self.offset + 8 <= self.buffer._size { + let value: Double = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Double.self).pointee + self.offset += 8 + return value + } + return nil + } + + public func readBytesAsInt32(_ count: Int) -> Int32? { + if count == 0 { + return 0 + } + else if count > 0 && count <= 4 || self.offset + UInt(count) <= self.buffer._size { + var value: Int32 = 0 + memcpy(&value, self.buffer.data?.advanced(by: Int(self.offset)), count) + self.offset += UInt(count) + return value + } + return nil + } + + public func readBuffer(_ count: Int) -> Buffer? { + if count >= 0 && self.offset + UInt(count) <= self.buffer._size { + let buffer = Buffer() + buffer.appendBytes((self.buffer.data?.advanced(by: Int(self.offset)))!, length: UInt(count)) + self.offset += UInt(count) + return buffer + } + return nil + } + + public func withReadBufferNoCopy(_ count: Int, _ f: (Buffer) -> T) -> T? { + if count >= 0 && self.offset + UInt(count) <= self.buffer._size { + return f(Buffer(memory: self.buffer.data!.advanced(by: Int(self.offset)), size: count, capacity: count, freeWhenDone: false)) + } + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/CacheStorageSettings.swift b/submodules/TelegramCore/TelegramCore/CacheStorageSettings.swift new file mode 100644 index 0000000000..0bb345caaf --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CacheStorageSettings.swift @@ -0,0 +1,58 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct CacheStorageSettings: PreferencesEntry, Equatable { + public let defaultCacheStorageTimeout: Int32 + + public static var defaultSettings: CacheStorageSettings { + return CacheStorageSettings(defaultCacheStorageTimeout: Int32.max) + } + + init(defaultCacheStorageTimeout: Int32) { + self.defaultCacheStorageTimeout = defaultCacheStorageTimeout + } + + public init(decoder: PostboxDecoder) { + self.defaultCacheStorageTimeout = decoder.decodeInt32ForKey("dt", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.defaultCacheStorageTimeout, forKey: "dt") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? CacheStorageSettings { + return self == to + } else { + return false + } + } + + public static func ==(lhs: CacheStorageSettings, rhs: CacheStorageSettings) -> Bool { + return lhs.defaultCacheStorageTimeout == rhs.defaultCacheStorageTimeout + } + + public func withUpdatedDefaultCacheStorageTimeout(_ defaultCacheStorageTimeout: Int32) -> CacheStorageSettings { + return CacheStorageSettings(defaultCacheStorageTimeout: defaultCacheStorageTimeout) + } +} + +public func updateCacheStorageSettingsInteractively(accountManager: AccountManager, _ f: @escaping (CacheStorageSettings) -> CacheStorageSettings) -> Signal { + return accountManager.transaction { transaction -> Void in + transaction.updateSharedData(SharedDataKeys.cacheStorageSettings, { entry in + let currentSettings: CacheStorageSettings + if let entry = entry as? CacheStorageSettings { + currentSettings = entry + } else { + currentSettings = CacheStorageSettings.defaultSettings + } + return f(currentSettings) + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedChannelData.swift b/submodules/TelegramCore/TelegramCore/CachedChannelData.swift new file mode 100644 index 0000000000..9f6b9a4be2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedChannelData.swift @@ -0,0 +1,412 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct CachedChannelFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let canDisplayParticipants = CachedChannelFlags(rawValue: 1 << 0) + public static let canChangeUsername = CachedChannelFlags(rawValue: 1 << 1) + public static let canSetStickerSet = CachedChannelFlags(rawValue: 1 << 2) + public static let preHistoryEnabled = CachedChannelFlags(rawValue: 1 << 3) + public static let canViewStats = CachedChannelFlags(rawValue: 1 << 4) +} + +public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable { + public let memberCount: Int32? + public let adminCount: Int32? + public let bannedCount: Int32? + public let kickedCount: Int32? + + init(memberCount: Int32?, adminCount: Int32?, bannedCount: Int32?, kickedCount: Int32?) { + self.memberCount = memberCount + self.adminCount = adminCount + self.bannedCount = bannedCount + self.kickedCount = kickedCount + } + + public init(decoder: PostboxDecoder) { + if let memberCount = decoder.decodeOptionalInt32ForKey("p.m") { + self.memberCount = memberCount + } else { + self.memberCount = nil + } + if let adminCount = decoder.decodeOptionalInt32ForKey("p.a") { + self.adminCount = adminCount + } else { + self.adminCount = nil + } + if let bannedCount = decoder.decodeOptionalInt32ForKey("p.b") { + self.bannedCount = bannedCount + } else { + self.bannedCount = nil + } + if let kickedCount = decoder.decodeOptionalInt32ForKey("p.k") { + self.kickedCount = kickedCount + } else { + self.kickedCount = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + if let memberCount = self.memberCount { + encoder.encodeInt32(memberCount, forKey: "p.m") + } else { + encoder.encodeNil(forKey: "p.m") + } + if let adminCount = self.adminCount { + encoder.encodeInt32(adminCount, forKey: "p.a") + } else { + encoder.encodeNil(forKey: "p.a") + } + if let bannedCount = self.bannedCount { + encoder.encodeInt32(bannedCount, forKey: "p.b") + } else { + encoder.encodeNil(forKey: "p.b") + } + if let kickedCount = self.kickedCount { + encoder.encodeInt32(kickedCount, forKey: "p.k") + } else { + encoder.encodeNil(forKey: "p.k") + } + } + + public static func ==(lhs: CachedChannelParticipantsSummary, rhs: CachedChannelParticipantsSummary) -> Bool { + return lhs.memberCount == rhs.memberCount && lhs.adminCount == rhs.adminCount && lhs.bannedCount == rhs.bannedCount && lhs.kickedCount == rhs.kickedCount + } + + public func withUpdatedMemberCount(_ memberCount: Int32?) -> CachedChannelParticipantsSummary { + return CachedChannelParticipantsSummary(memberCount: memberCount, adminCount: self.adminCount, bannedCount: self.bannedCount, kickedCount: self.kickedCount) + } + + public func withUpdatedAdminCount(_ adminCount: Int32?) -> CachedChannelParticipantsSummary { + return CachedChannelParticipantsSummary(memberCount: self.memberCount, adminCount: adminCount, bannedCount: self.bannedCount, kickedCount: self.kickedCount) + } + + public func withUpdatedBannedCount(_ bannedCount: Int32?) -> CachedChannelParticipantsSummary { + return CachedChannelParticipantsSummary(memberCount: self.memberCount, adminCount: self.adminCount, bannedCount: bannedCount, kickedCount: self.kickedCount) + } + + public func withUpdatedKickedCount(_ kickedCount: Int32?) -> CachedChannelParticipantsSummary { + return CachedChannelParticipantsSummary(memberCount: self.memberCount, adminCount: self.adminCount, bannedCount: self.bannedCount, kickedCount: kickedCount) + } +} + +public struct ChannelMigrationReference: PostboxCoding, Equatable { + public let maxMessageId: MessageId + + public init(maxMessageId: MessageId) { + self.maxMessageId = maxMessageId + } + + public init(decoder: PostboxDecoder) { + self.maxMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: decoder.decodeInt32ForKey("n", orElse: 0), id: decoder.decodeInt32ForKey("i", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.maxMessageId.peerId.toInt64(), forKey: "p") + encoder.encodeInt32(self.maxMessageId.namespace, forKey: "n") + encoder.encodeInt32(self.maxMessageId.id, forKey: "i") + } + + public static func ==(lhs: ChannelMigrationReference, rhs: ChannelMigrationReference) -> Bool { + return lhs.maxMessageId == rhs.maxMessageId + } +} + +public final class CachedChannelData: CachedPeerData { + public let isNotAccessible: Bool + public let flags: CachedChannelFlags + public let about: String? + public let participantsSummary: CachedChannelParticipantsSummary + public let exportedInvitation: ExportedInvitation? + public let botInfos: [CachedPeerBotInfo] + public let peerStatusSettings: PeerStatusSettings? + public let pinnedMessageId: MessageId? + public let stickerPack: StickerPackCollectionInfo? + public let minAvailableMessageId: MessageId? + public let migrationReference: ChannelMigrationReference? + + public let linkedDiscussionPeerId: PeerId? + + public let peerIds: Set + public let messageIds: Set + public var associatedHistoryMessageId: MessageId? { + return self.migrationReference?.maxMessageId + } + + init() { + self.isNotAccessible = false + self.flags = [] + self.about = nil + self.participantsSummary = CachedChannelParticipantsSummary(memberCount: nil, adminCount: nil, bannedCount: nil, kickedCount: nil) + self.exportedInvitation = nil + self.botInfos = [] + self.peerStatusSettings = nil + self.pinnedMessageId = nil + self.peerIds = Set() + self.messageIds = Set() + self.stickerPack = nil + self.minAvailableMessageId = nil + self.migrationReference = nil + self.linkedDiscussionPeerId = nil + } + + init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?) { + self.isNotAccessible = isNotAccessible + self.flags = flags + self.about = about + self.participantsSummary = participantsSummary + self.exportedInvitation = exportedInvitation + self.botInfos = botInfos + self.peerStatusSettings = peerStatusSettings + self.pinnedMessageId = pinnedMessageId + self.stickerPack = stickerPack + self.minAvailableMessageId = minAvailableMessageId + self.migrationReference = migrationReference + self.linkedDiscussionPeerId = linkedDiscussionPeerId + + var peerIds = Set() + for botInfo in botInfos { + peerIds.insert(botInfo.peerId) + } + + if let linkedDiscussionPeerId = linkedDiscussionPeerId { + peerIds.insert(linkedDiscussionPeerId) + } + + self.peerIds = peerIds + + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + } + + func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { + return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedAbout(_ about: String?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId) + } + + func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId) + } + + public init(decoder: PostboxDecoder) { + self.isNotAccessible = decoder.decodeInt32ForKey("isNotAccessible", orElse: 0) != 0 + self.flags = CachedChannelFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.about = decoder.decodeOptionalStringForKey("a") + self.participantsSummary = CachedChannelParticipantsSummary(decoder: decoder) + self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation + self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] + var peerIds = Set() + if let value = decoder.decodeOptionalInt32ForKey("pcs") { + self.peerStatusSettings = PeerStatusSettings(rawValue: value) + } else { + self.peerStatusSettings = nil + } + if let pinnedMessagePeerId = decoder.decodeOptionalInt64ForKey("pm.p"), let pinnedMessageNamespace = decoder.decodeOptionalInt32ForKey("pm.n"), let pinnedMessageId = decoder.decodeOptionalInt32ForKey("pm.i") { + self.pinnedMessageId = MessageId(peerId: PeerId(pinnedMessagePeerId), namespace: pinnedMessageNamespace, id: pinnedMessageId) + } else { + self.pinnedMessageId = nil + } + + if let stickerPack = decoder.decodeObjectForKey("sp", decoder: { StickerPackCollectionInfo(decoder: $0) }) as? StickerPackCollectionInfo { + self.stickerPack = stickerPack + } else { + self.stickerPack = nil + } + + if let minAvailableMessagePeerId = decoder.decodeOptionalInt64ForKey("ma.p"), let minAvailableMessageNamespace = decoder.decodeOptionalInt32ForKey("ma.n"), let minAvailableMessageId = decoder.decodeOptionalInt32ForKey("ma.i") { + self.minAvailableMessageId = MessageId(peerId: PeerId(minAvailableMessagePeerId), namespace: minAvailableMessageNamespace, id: minAvailableMessageId) + } else { + self.minAvailableMessageId = nil + } + + self.migrationReference = decoder.decodeObjectForKey("mr", decoder: { ChannelMigrationReference(decoder: $0) }) as? ChannelMigrationReference + + for botInfo in self.botInfos { + peerIds.insert(botInfo.peerId) + } + + if let linkedDiscussionPeerId = decoder.decodeOptionalInt64ForKey("dgi") { + self.linkedDiscussionPeerId = PeerId(linkedDiscussionPeerId) + } else { + self.linkedDiscussionPeerId = nil + } + + if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { + peerIds.insert(linkedDiscussionPeerId) + } + + self.peerIds = peerIds + + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.isNotAccessible ? 1 : 0, forKey: "isNotAccessible") + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + if let about = self.about { + encoder.encodeString(about, forKey: "a") + } else { + encoder.encodeNil(forKey: "a") + } + self.participantsSummary.encode(encoder) + if let exportedInvitation = self.exportedInvitation { + encoder.encodeObject(exportedInvitation, forKey: "i") + } else { + encoder.encodeNil(forKey: "i") + } + encoder.encodeObjectArray(self.botInfos, forKey: "b") + if let peerStatusSettings = self.peerStatusSettings { + encoder.encodeInt32(peerStatusSettings.rawValue, forKey: "pcs") + } else { + encoder.encodeNil(forKey: "pcs") + } + if let pinnedMessageId = self.pinnedMessageId { + encoder.encodeInt64(pinnedMessageId.peerId.toInt64(), forKey: "pm.p") + encoder.encodeInt32(pinnedMessageId.namespace, forKey: "pm.n") + encoder.encodeInt32(pinnedMessageId.id, forKey: "pm.i") + } else { + encoder.encodeNil(forKey: "pm.p") + encoder.encodeNil(forKey: "pm.n") + encoder.encodeNil(forKey: "pm.i") + } + if let stickerPack = self.stickerPack { + encoder.encodeObject(stickerPack, forKey: "sp") + } else { + encoder.encodeNil(forKey: "sp") + } + if let minAvailableMessageId = self.minAvailableMessageId { + encoder.encodeInt64(minAvailableMessageId.peerId.toInt64(), forKey: "ma.p") + encoder.encodeInt32(minAvailableMessageId.namespace, forKey: "ma.n") + encoder.encodeInt32(minAvailableMessageId.id, forKey: "ma.i") + } else { + encoder.encodeNil(forKey: "ma.p") + encoder.encodeNil(forKey: "ma.n") + encoder.encodeNil(forKey: "ma.i") + } + if let migrationReference = self.migrationReference { + encoder.encodeObject(migrationReference, forKey: "mr") + } else { + encoder.encodeNil(forKey: "mr") + } + if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { + encoder.encodeInt64(linkedDiscussionPeerId.toInt64(), forKey: "dgi") + } else { + encoder.encodeNil(forKey: "dgi") + } + } + + public func isEqual(to: CachedPeerData) -> Bool { + guard let other = to as? CachedChannelData else { + return false + } + + if other.isNotAccessible != self.isNotAccessible { + return false + } + + if other.flags != self.flags { + return false + } + + if other.linkedDiscussionPeerId != self.linkedDiscussionPeerId { + return false + } + + if other.about != self.about { + return false + } + + if other.participantsSummary != self.participantsSummary { + return false + } + + if other.exportedInvitation != self.exportedInvitation { + return false + } + + if other.botInfos != self.botInfos { + return false + } + + if other.peerStatusSettings != self.peerStatusSettings { + return false + } + + if other.pinnedMessageId != self.pinnedMessageId { + return false + } + + if other.stickerPack != self.stickerPack { + return false + } + + if other.minAvailableMessageId != self.minAvailableMessageId { + return false + } + + if other.migrationReference != self.migrationReference { + return false + } + + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedChannelParticipants.swift b/submodules/TelegramCore/TelegramCore/CachedChannelParticipants.swift new file mode 100644 index 0000000000..72e8634771 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedChannelParticipants.swift @@ -0,0 +1,195 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private enum ChannelParticipantValue: Int32 { + case member = 0 + case creator = 1 + case editor = 2 + case moderator = 3 +} + +public struct ChannelParticipantAdminInfo: PostboxCoding, Equatable { + public let rights: TelegramChatAdminRights + public let promotedBy: PeerId + public let canBeEditedByAccountPeer: Bool + + public init(rights: TelegramChatAdminRights, promotedBy: PeerId, canBeEditedByAccountPeer: Bool) { + self.rights = rights + self.promotedBy = promotedBy + self.canBeEditedByAccountPeer = canBeEditedByAccountPeer + } + + public init(decoder: PostboxDecoder) { + self.rights = decoder.decodeObjectForKey("r", decoder: { TelegramChatAdminRights(decoder: $0) }) as! TelegramChatAdminRights + self.promotedBy = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.canBeEditedByAccountPeer = decoder.decodeInt32ForKey("e", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.rights, forKey: "r") + encoder.encodeInt64(self.promotedBy.toInt64(), forKey: "p") + encoder.encodeInt32(self.canBeEditedByAccountPeer ? 1 : 0, forKey: "e") + } + + public static func ==(lhs: ChannelParticipantAdminInfo, rhs: ChannelParticipantAdminInfo) -> Bool { + return lhs.rights == rhs.rights && lhs.promotedBy == rhs.promotedBy && lhs.canBeEditedByAccountPeer == rhs.canBeEditedByAccountPeer + } +} + +public struct ChannelParticipantBannedInfo: PostboxCoding, Equatable { + public let rights: TelegramChatBannedRights + public let restrictedBy: PeerId + public let timestamp: Int32 + public let isMember: Bool + + public init(rights: TelegramChatBannedRights, restrictedBy: PeerId, timestamp: Int32, isMember: Bool) { + self.rights = rights + self.restrictedBy = restrictedBy + self.timestamp = timestamp + self.isMember = isMember + } + + public init(decoder: PostboxDecoder) { + self.rights = decoder.decodeObjectForKey("r", decoder: { TelegramChatBannedRights(decoder: $0) }) as! TelegramChatBannedRights + self.restrictedBy = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + self.isMember = decoder.decodeInt32ForKey("m", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.rights, forKey: "r") + encoder.encodeInt64(self.restrictedBy.toInt64(), forKey: "p") + encoder.encodeInt32(self.timestamp, forKey: "t") + encoder.encodeInt32(self.isMember ? 1 : 0, forKey: "m") + } + + public static func ==(lhs: ChannelParticipantBannedInfo, rhs: ChannelParticipantBannedInfo) -> Bool { + return lhs.rights == rhs.rights && lhs.restrictedBy == rhs.restrictedBy && lhs.timestamp == rhs.timestamp && lhs.isMember == rhs.isMember + } +} + +public enum ChannelParticipant: PostboxCoding, Equatable { + case creator(id: PeerId) + case member(id: PeerId, invitedAt: Int32, adminInfo: ChannelParticipantAdminInfo?, banInfo: ChannelParticipantBannedInfo?) + + public var peerId: PeerId { + switch self { + case let .creator(id): + return id + case let .member(id, _, _, _): + return id + } + } + + public static func ==(lhs: ChannelParticipant, rhs: ChannelParticipant) -> Bool { + switch lhs { + case let .member(lhsId, lhsInvitedAt, lhsAdminInfo, lhsBanInfo): + if case let .member(rhsId, rhsInvitedAt, rhsAdminInfo, rhsBanInfo) = rhs { + if lhsId != rhsId { + return false + } + if lhsInvitedAt != rhsInvitedAt { + return false + } + if lhsAdminInfo != rhsAdminInfo { + return false + } + if lhsBanInfo != rhsBanInfo { + return false + } + return true + } else { + return false + } + case let .creator(id): + if case .creator(id) = rhs { + return true + } else { + return false + } + } + } + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case ChannelParticipantValue.member.rawValue: + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0), adminInfo: decoder.decodeObjectForKey("ai", decoder: { ChannelParticipantAdminInfo(decoder: $0) }) as? ChannelParticipantAdminInfo, banInfo: decoder.decodeObjectForKey("bi", decoder: { ChannelParticipantBannedInfo(decoder: $0) }) as? ChannelParticipantBannedInfo) + case ChannelParticipantValue.creator.rawValue: + self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) + default: + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0), adminInfo: nil, banInfo: nil) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .member(id, invitedAt, adminInfo, banInfo): + encoder.encodeInt32(ChannelParticipantValue.member.rawValue, forKey: "r") + encoder.encodeInt64(id.toInt64(), forKey: "i") + encoder.encodeInt32(invitedAt, forKey: "t") + if let adminInfo = adminInfo { + encoder.encodeObject(adminInfo, forKey: "ai") + } else { + encoder.encodeNil(forKey: "ai") + } + if let banInfo = banInfo { + encoder.encodeObject(banInfo, forKey: "bi") + } else { + encoder.encodeNil(forKey: "bi") + } + case let .creator(id): + encoder.encodeInt32(ChannelParticipantValue.creator.rawValue, forKey: "r") + encoder.encodeInt64(id.toInt64(), forKey: "i") + } + } +} + +public final class CachedChannelParticipants: PostboxCoding, Equatable { + public let participants: [ChannelParticipant] + + init(participants: [ChannelParticipant]) { + self.participants = participants + } + + public init(decoder: PostboxDecoder) { + self.participants = decoder.decodeObjectArrayWithDecoderForKey("p") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.participants, forKey: "p") + } + + public static func ==(lhs: CachedChannelParticipants, rhs: CachedChannelParticipants) -> Bool { + return lhs.participants == rhs.participants + } +} + + +extension ChannelParticipant { + init(apiParticipant: Api.ChannelParticipant) { + switch apiParticipant { + case let .channelParticipant(userId, date): + self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: nil, banInfo: nil) + case let .channelParticipantCreator(userId): + self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + case let .channelParticipantBanned(flags, userId, restrictedBy, date, bannedRights): + let hasLeft = (flags & (1 << 0)) != 0 + let banInfo = ChannelParticipantBannedInfo(rights: TelegramChatBannedRights(apiBannedRights: bannedRights), restrictedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: restrictedBy), timestamp: date, isMember: !hasLeft) + self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: nil, banInfo: banInfo) + case let .channelParticipantAdmin(flags, userId, _, promotedBy, date, adminRights): + self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: promotedBy), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil) + case let .channelParticipantSelf(userId, _, date): + self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: nil, banInfo: nil) + } + } +} + +extension CachedChannelParticipants { + convenience init(apiParticipants: [Api.ChannelParticipant]) { + self.init(participants: apiParticipants.map(ChannelParticipant.init)) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedGroupData.swift b/submodules/TelegramCore/TelegramCore/CachedGroupData.swift new file mode 100644 index 0000000000..5fb88ed969 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedGroupData.swift @@ -0,0 +1,204 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class CachedPeerBotInfo: PostboxCoding, Equatable { + public let peerId: PeerId + public let botInfo: BotInfo + + init(peerId: PeerId, botInfo: BotInfo) { + self.peerId = peerId + self.botInfo = botInfo + } + + public init(decoder: PostboxDecoder) { + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.botInfo = decoder.decodeObjectForKey("i", decoder: { return BotInfo(decoder: $0) }) as! BotInfo + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.peerId.toInt64(), forKey: "p") + encoder.encodeObject(self.botInfo, forKey: "i") + } + + public static func ==(lhs: CachedPeerBotInfo, rhs: CachedPeerBotInfo) -> Bool { + return lhs.peerId == rhs.peerId && lhs.botInfo == rhs.botInfo + } +} + +public struct CachedGroupFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let canChangeUsername = CachedGroupFlags(rawValue: 1 << 0) +} + +public final class CachedGroupData: CachedPeerData { + public let participants: CachedGroupParticipants? + public let exportedInvitation: ExportedInvitation? + public let botInfos: [CachedPeerBotInfo] + public let peerStatusSettings: PeerStatusSettings? + public let pinnedMessageId: MessageId? + public let about: String? + public let flags: CachedGroupFlags + + public let peerIds: Set + public let messageIds: Set + public let associatedHistoryMessageId: MessageId? = nil + + init() { + self.participants = nil + self.exportedInvitation = nil + self.botInfos = [] + self.peerStatusSettings = nil + self.pinnedMessageId = nil + self.messageIds = Set() + self.peerIds = Set() + self.about = nil + self.flags = CachedGroupFlags() + } + + public init(participants: CachedGroupParticipants?, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, about: String?, flags: CachedGroupFlags) { + self.participants = participants + self.exportedInvitation = exportedInvitation + self.botInfos = botInfos + self.peerStatusSettings = peerStatusSettings + self.pinnedMessageId = pinnedMessageId + self.about = about + self.flags = flags + + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + + var peerIds = Set() + if let participants = participants { + for participant in participants.participants { + peerIds.insert(participant.peerId) + } + } + for botInfo in botInfos { + peerIds.insert(botInfo.peerId) + } + self.peerIds = peerIds + } + + public init(decoder: PostboxDecoder) { + let participants = decoder.decodeObjectForKey("p", decoder: { CachedGroupParticipants(decoder: $0) }) as? CachedGroupParticipants + self.participants = participants + self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation + self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] + if let value = decoder.decodeOptionalInt32ForKey("pcs") { + self.peerStatusSettings = PeerStatusSettings(rawValue: value) + } else { + self.peerStatusSettings = nil + } + if let pinnedMessagePeerId = decoder.decodeOptionalInt64ForKey("pm.p"), let pinnedMessageNamespace = decoder.decodeOptionalInt32ForKey("pm.n"), let pinnedMessageId = decoder.decodeOptionalInt32ForKey("pm.i") { + self.pinnedMessageId = MessageId(peerId: PeerId(pinnedMessagePeerId), namespace: pinnedMessageNamespace, id: pinnedMessageId) + } else { + self.pinnedMessageId = nil + } + self.about = decoder.decodeOptionalStringForKey("ab") + self.flags = CachedGroupFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0)) + + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + + var peerIds = Set() + if let participants = participants { + for participant in participants.participants { + peerIds.insert(participant.peerId) + } + } + for botInfo in self.botInfos { + peerIds.insert(botInfo.peerId) + } + + self.peerIds = peerIds + } + + public func encode(_ encoder: PostboxEncoder) { + if let participants = self.participants { + encoder.encodeObject(participants, forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + if let exportedInvitation = self.exportedInvitation { + encoder.encodeObject(exportedInvitation, forKey: "i") + } else { + encoder.encodeNil(forKey: "i") + } + encoder.encodeObjectArray(self.botInfos, forKey: "b") + if let peerStatusSettings = self.peerStatusSettings { + encoder.encodeInt32(peerStatusSettings.rawValue, forKey: "pcs") + } else { + encoder.encodeNil(forKey: "pcs") + } + if let pinnedMessageId = self.pinnedMessageId { + encoder.encodeInt64(pinnedMessageId.peerId.toInt64(), forKey: "pm.p") + encoder.encodeInt32(pinnedMessageId.namespace, forKey: "pm.n") + encoder.encodeInt32(pinnedMessageId.id, forKey: "pm.i") + } else { + encoder.encodeNil(forKey: "pm.p") + encoder.encodeNil(forKey: "pm.n") + encoder.encodeNil(forKey: "pm.i") + } + if let about = self.about { + encoder.encodeString(about, forKey: "ab") + } else { + encoder.encodeNil(forKey: "ab") + } + encoder.encodeInt32(self.flags.rawValue, forKey: "fl") + } + + public func isEqual(to: CachedPeerData) -> Bool { + guard let other = to as? CachedGroupData else { + return false + } + + return self.participants == other.participants && self.exportedInvitation == other.exportedInvitation && self.botInfos == other.botInfos && self.peerStatusSettings == other.peerStatusSettings && self.pinnedMessageId == other.pinnedMessageId && self.about == other.about && self.flags == other.flags + } + + func withUpdatedParticipants(_ participants: CachedGroupParticipants?) -> CachedGroupData { + return CachedGroupData(participants: participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags) + } + + func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags) + } + + func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags) + } + + func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags) + } + + func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, about: self.about, flags: self.flags) + } + + func withUpdatedAbout(_ about: String?) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: about, flags: self.flags) + } + + func withUpdatedFlags(_ flags: CachedGroupFlags) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: flags) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedGroupParticipants.swift b/submodules/TelegramCore/TelegramCore/CachedGroupParticipants.swift new file mode 100644 index 0000000000..c8ed1cdb73 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedGroupParticipants.swift @@ -0,0 +1,136 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum GroupParticipant: PostboxCoding, Equatable { + case member(id: PeerId, invitedBy: PeerId, invitedAt: Int32) + case creator(id: PeerId) + case admin(id: PeerId, invitedBy: PeerId, invitedAt: Int32) + + public var peerId: PeerId { + switch self { + case let .member(id, _, _): + return id + case let .creator(id): + return id + case let .admin(id, _, _): + return id + } + } + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case 0: + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) + case 1: + self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) + case 2: + self = .admin(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) + default: + self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0)) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .member(id, invitedBy, invitedAt): + encoder.encodeInt32(0, forKey: "v") + encoder.encodeInt64(id.toInt64(), forKey: "i") + encoder.encodeInt64(invitedBy.toInt64(), forKey: "b") + encoder.encodeInt32(invitedAt, forKey: "t") + case let .creator(id): + encoder.encodeInt32(1, forKey: "v") + encoder.encodeInt64(id.toInt64(), forKey: "i") + case let .admin(id, invitedBy, invitedAt): + encoder.encodeInt32(2, forKey: "v") + encoder.encodeInt64(id.toInt64(), forKey: "i") + encoder.encodeInt64(invitedBy.toInt64(), forKey: "b") + encoder.encodeInt32(invitedAt, forKey: "t") + } + } + + public static func ==(lhs: GroupParticipant, rhs: GroupParticipant) -> Bool { + switch lhs { + case let .admin(lhsId, lhIinvitedBy, lhsInvitedAt): + if case .admin(lhsId, lhIinvitedBy, lhsInvitedAt) = rhs { + return true + } else { + return false + } + case let .creator(lhsId): + if case .creator(lhsId) = rhs { + return true + } else { + return false + } + case let .member(lhsId, lhIinvitedBy, lhsInvitedAt): + if case .member(lhsId, lhIinvitedBy, lhsInvitedAt) = rhs { + return true + } else { + return false + } + } + } + + public var invitedBy: PeerId { + switch self { + case let .admin(_, invitedBy, _): + return invitedBy + case let .member(_, invitedBy, _): + return invitedBy + case let .creator(id): + return id + } + } +} + +public final class CachedGroupParticipants: PostboxCoding, Equatable { + public let participants: [GroupParticipant] + let version: Int32 + + init(participants: [GroupParticipant], version: Int32) { + self.participants = participants + self.version = version + } + + public init(decoder: PostboxDecoder) { + self.participants = decoder.decodeObjectArrayWithDecoderForKey("p") + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.participants, forKey: "p") + encoder.encodeInt32(self.version, forKey: "v") + } + + public static func ==(lhs: CachedGroupParticipants, rhs: CachedGroupParticipants) -> Bool { + return lhs.version == rhs.version && lhs.participants == rhs.participants + } +} + +extension GroupParticipant { + init(apiParticipant: Api.ChatParticipant) { + switch apiParticipant { + case let .chatParticipantCreator(userId): + self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + case let .chatParticipantAdmin(userId, inviterId, date): + self = .admin(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId), invitedAt: date) + case let .chatParticipant(userId, inviterId, date): + self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId), invitedAt: date) + } + } +} + +extension CachedGroupParticipants { + convenience init?(apiParticipants: Api.ChatParticipants) { + switch apiParticipants { + case let .chatParticipants(_, participants, version): + self.init(participants: participants.map { GroupParticipant(apiParticipant: $0) }, version: version) + case .chatParticipantsForbidden: + return nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedSentMediaReferences.swift b/submodules/TelegramCore/TelegramCore/CachedSentMediaReferences.swift new file mode 100644 index 0000000000..f2079a6d05 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedSentMediaReferences.swift @@ -0,0 +1,44 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private let cachedSentMediaCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000) + +enum CachedSentMediaReferenceKey { + case image(hash: Data) + case file(hash: Data) + + var key: ValueBoxKey { + switch self { + case let .image(hash): + let result = ValueBoxKey(length: 1 + hash.count) + result.setUInt8(0, value: 0) + hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(result.memory.advanced(by: 1), bytes, hash.count) + } + return result + case let .file(hash): + let result = ValueBoxKey(length: 1 + hash.count) + result.setUInt8(0, value: 1) + hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(result.memory.advanced(by: 1), bytes, hash.count) + } + return result + } + } +} + +func cachedSentMediaReference(postbox: Postbox, key: CachedSentMediaReferenceKey) -> Signal { + return postbox.transaction { transaction -> Media? in + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key)) as? Media + } +} + +func storeCachedSentMediaReference(transaction: Transaction, key: CachedSentMediaReferenceKey, media: Media) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media, collectionSpec: cachedSentMediaCollectionSpec) +} diff --git a/submodules/TelegramCore/TelegramCore/CachedStickerPack.swift b/submodules/TelegramCore/TelegramCore/CachedStickerPack.swift new file mode 100644 index 0000000000..e4ff40533f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedStickerPack.swift @@ -0,0 +1,123 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +final class CachedStickerPack: PostboxCoding { + let info: StickerPackCollectionInfo? + let items: [StickerPackItem] + let hash: Int32 + + init(info: StickerPackCollectionInfo?, items: [StickerPackItem], hash: Int32) { + self.info = info + self.items = items + self.hash = hash + } + + init(decoder: PostboxDecoder) { + self.info = decoder.decodeObjectForKey("in", decoder: { StickerPackCollectionInfo(decoder: $0) }) as? StickerPackCollectionInfo + self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! StickerPackItem } + self.hash = decoder.decodeInt32ForKey("h", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + if let info = self.info { + encoder.encodeObject(info, forKey: "in") + } else { + encoder.encodeNil(forKey: "in") + } + encoder.encodeObjectArray(self.items, forKey: "it") + encoder.encodeInt32(self.hash, forKey: "h") + } + + static func cacheKey(_ id: ItemCollectionId) -> ValueBoxKey { + let key = ValueBoxKey(length: 4 + 8) + key.setInt32(0, value: id.namespace) + key.setInt64(4, value: id.id) + return key + } +} + +private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200) + +public enum CachedStickerPackResult { + case none + case fetching + case result(StickerPackCollectionInfo, [ItemCollectionItem], Bool) +} + +func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, items: [ItemCollectionItem]) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) +} + +public func cachedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceRemote: Bool) -> Signal { + return postbox.transaction { transaction -> CachedStickerPackResult? in + if let (info, items, local) = cachedStickerPack(transaction: transaction, reference: reference) { + if local { + return .result(info, items, true) + } + } + return nil + } |> mapToSignal { value -> Signal in + if let value = value { + return .single(value) + } else { + return postbox.transaction { transaction -> (CachedStickerPackResult, Bool, Int32?) in + var loadRemote = false + let namespace = Namespaces.ItemCollection.CloudStickerPacks + var previousHash: Int32? + if case let .id(id, _) = reference, let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + previousHash = cached.hash + let current: CachedStickerPackResult = .result(info, cached.items, false) + if cached.hash != info.hash { + return (current, true, previousHash) + } else { + return (current, false, previousHash) + } + } else { + return (.fetching, true, nil) + } + } |> mapToSignal { result, loadRemote, previousHash in + if loadRemote || forceRemote { + let appliedRemote = updatedRemoteStickerPack(postbox: postbox, network: network, reference: reference) + |> mapToSignal { result -> Signal in + if let result = result, result.0.hash == previousHash { + return .complete() + } + return postbox.transaction { transaction -> CachedStickerPackResult in + if let result = result { + cacheStickerPack(transaction: transaction, info: result.0, items: result.1) + + let currentInfo = transaction.getItemCollectionInfo(collectionId: result.0.id) as? StickerPackCollectionInfo + + return .result(result.0, result.1, currentInfo != nil) + } else { + return .none + } + } + } + return .single(result) |> then(appliedRemote) + } else { + return .single(result) + } + } + } + } +} + +func cachedStickerPack(transaction: Transaction, reference: StickerPackReference) -> (StickerPackCollectionInfo, [ItemCollectionItem], Bool)? { + let namespace = Namespaces.ItemCollection.CloudStickerPacks + if case let .id(id, _) = reference, let currentInfo = transaction.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: namespace, id: id)) as? StickerPackCollectionInfo { + let items = transaction.getItemCollectionItems(collectionId: ItemCollectionId(namespace: namespace, id: id)) + return (currentInfo, items, true) + } else { + if case let .id(id, _) = reference, let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + return (info, cached.items, false) + } + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/CachedUserData.swift b/submodules/TelegramCore/TelegramCore/CachedUserData.swift new file mode 100644 index 0000000000..6aa16f0065 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CachedUserData.swift @@ -0,0 +1,161 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class CachedUserData: CachedPeerData { + public let about: String? + public let botInfo: BotInfo? + public let peerStatusSettings: PeerStatusSettings? + public let pinnedMessageId: MessageId? + public let isBlocked: Bool + public let commonGroupCount: Int32 + public let callsAvailable: Bool + public let callsPrivate: Bool + public let canPinMessages: Bool + + public let peerIds = Set() + public let messageIds: Set + public let associatedHistoryMessageId: MessageId? = nil + + init() { + self.about = nil + self.botInfo = nil + self.peerStatusSettings = nil + self.pinnedMessageId = nil + self.isBlocked = false + self.commonGroupCount = 0 + self.callsAvailable = false + self.callsPrivate = false + self.canPinMessages = false + self.messageIds = Set() + } + + init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, callsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool) { + self.about = about + self.botInfo = botInfo + self.peerStatusSettings = peerStatusSettings + self.pinnedMessageId = pinnedMessageId + self.isBlocked = isBlocked + self.commonGroupCount = commonGroupCount + self.callsAvailable = callsAvailable + self.callsPrivate = callsPrivate + self.canPinMessages = canPinMessages + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + } + + public init(decoder: PostboxDecoder) { + self.about = decoder.decodeOptionalStringForKey("a") + self.botInfo = decoder.decodeObjectForKey("bi") as? BotInfo + if let value = decoder.decodeOptionalInt32ForKey("pcs") { + self.peerStatusSettings = PeerStatusSettings(rawValue: value) + } else { + self.peerStatusSettings = nil + } + if let pinnedMessagePeerId = decoder.decodeOptionalInt64ForKey("pm.p"), let pinnedMessageNamespace = decoder.decodeOptionalInt32ForKey("pm.n"), let pinnedMessageId = decoder.decodeOptionalInt32ForKey("pm.i") { + self.pinnedMessageId = MessageId(peerId: PeerId(pinnedMessagePeerId), namespace: pinnedMessageNamespace, id: pinnedMessageId) + } else { + self.pinnedMessageId = nil + } + self.isBlocked = decoder.decodeInt32ForKey("b", orElse: 0) != 0 + self.commonGroupCount = decoder.decodeInt32ForKey("cg", orElse: 0) + self.callsAvailable = decoder.decodeInt32ForKey("ca", orElse: 0) != 0 + self.callsPrivate = decoder.decodeInt32ForKey("cp", orElse: 0) != 0 + self.canPinMessages = decoder.decodeInt32ForKey("cpm", orElse: 0) != 0 + + var messageIds = Set() + if let pinnedMessageId = self.pinnedMessageId { + messageIds.insert(pinnedMessageId) + } + self.messageIds = messageIds + } + + public func encode(_ encoder: PostboxEncoder) { + if let about = self.about { + encoder.encodeString(about, forKey: "a") + } else { + encoder.encodeNil(forKey: "a") + } + if let botInfo = self.botInfo { + encoder.encodeObject(botInfo, forKey: "bi") + } else { + encoder.encodeNil(forKey: "bi") + } + if let peerStatusSettings = self.peerStatusSettings { + encoder.encodeInt32(peerStatusSettings.rawValue, forKey: "pcs") + } else { + encoder.encodeNil(forKey: "pcs") + } + if let pinnedMessageId = self.pinnedMessageId { + encoder.encodeInt64(pinnedMessageId.peerId.toInt64(), forKey: "pm.p") + encoder.encodeInt32(pinnedMessageId.namespace, forKey: "pm.n") + encoder.encodeInt32(pinnedMessageId.id, forKey: "pm.i") + } else { + encoder.encodeNil(forKey: "pm.p") + encoder.encodeNil(forKey: "pm.n") + encoder.encodeNil(forKey: "pm.i") + } + encoder.encodeInt32(self.isBlocked ? 1 : 0, forKey: "b") + encoder.encodeInt32(self.commonGroupCount, forKey: "cg") + encoder.encodeInt32(self.callsAvailable ? 1 : 0, forKey: "ca") + encoder.encodeInt32(self.callsPrivate ? 1 : 0, forKey: "cp") + encoder.encodeInt32(self.canPinMessages ? 1 : 0, forKey: "cpm") + } + + public func isEqual(to: CachedPeerData) -> Bool { + guard let other = to as? CachedUserData else { + return false + } + + if other.pinnedMessageId != self.pinnedMessageId { + return false + } + if other.canPinMessages != self.canPinMessages { + return false + } + + return other.about == self.about && other.botInfo == self.botInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.callsAvailable == other.callsAvailable && self.callsPrivate == other.callsPrivate + } + + func withUpdatedAbout(_ about: String?) -> CachedUserData { + return CachedUserData(about: about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedCallsAvailable(_ callsAvailable: Bool) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages) + } + + func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CallSessionManager.swift b/submodules/TelegramCore/TelegramCore/CallSessionManager.swift new file mode 100644 index 0000000000..9c99777ab1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CallSessionManager.swift @@ -0,0 +1,1013 @@ +import Foundation +#if os(macOS) +import PostboxMac +import MtProtoKitMac +import SwiftSignalKitMac +#else +import Postbox +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +import SwiftSignalKit +#endif + +private let minLayer: Int32 = 65 + +public enum CallSessionError: Equatable { + case generic + case privacyRestricted + case notSupportedByPeer + case serverProvided(String) + case disconnected + + public static func ==(lhs: CallSessionError, rhs: CallSessionError) -> Bool { + switch lhs { + case .generic: + if case .generic = rhs { + return true + } else { + return false + } + case .privacyRestricted: + if case .privacyRestricted = rhs { + return true + } else { + return false + } + case .notSupportedByPeer: + if case .notSupportedByPeer = rhs { + return true + } else { + return false + } + case let .serverProvided(text): + if case .serverProvided(text) = rhs { + return true + } else { + return false + } + case .disconnected: + if case .disconnected = rhs { + return true + } else { + return false + } + } + } +} + +public enum CallSessionEndedType { + case hungUp + case busy + case missed +} + +public enum CallSessionTerminationReason: Equatable { + case ended(CallSessionEndedType) + case error(CallSessionError) + + public static func ==(lhs: CallSessionTerminationReason, rhs: CallSessionTerminationReason) -> Bool { + switch lhs { + case let .ended(type): + if case .ended(type) = rhs { + return true + } else { + return false + } + case let .error(error): + if case .error(error) = rhs { + return true + } else { + return false + } + } + } +} + +public struct CallId: Equatable { + public let id: Int64 + public let accessHash: Int64 + + public init(id: Int64, accessHash: Int64) { + self.id = id + self.accessHash = accessHash + } +} + +enum CallSessionInternalState { + case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data) + case accepting(id: Int64, accessHash: Int64, gAHash: Data, b: Data, disposable: Disposable) + case awaitingConfirmation(id: Int64, accessHash: Int64, gAHash: Data, b: Data, config: SecretChatEncryptionConfig) + case requesting(a: Data, disposable: Disposable) + case requested(id: Int64, accessHash: Int64, a: Data, gA: Data, config: SecretChatEncryptionConfig, remoteConfirmationTimestamp: Int32?) + case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: Data, disposable: Disposable) + case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, allowsP2P: Bool) + case dropping(Disposable) + case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool) +} + +public typealias CallSessionInternalId = UUID +typealias CallSessionStableId = Int64 + +public struct CallSessionRingingState: Equatable { + public let id: CallSessionInternalId + public let peerId: PeerId + + public static func ==(lhs: CallSessionRingingState, rhs: CallSessionRingingState) -> Bool { + return lhs.id == rhs.id && lhs.peerId == rhs.peerId + } +} + +public enum DropCallReason { + case hangUp + case busy + case disconnect + case missed +} + +public struct CallTerminationOptions: OptionSet { + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let reportRating = CallTerminationOptions(rawValue: 1 << 0) + public static let sendDebugLogs = CallTerminationOptions(rawValue: 1 << 1) +} + +public enum CallSessionState { + case ringing + case accepting + case requesting(ringing: Bool) + case active(id: CallId, key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, allowsP2P: Bool) + case dropping + case terminated(id: CallId?, reason: CallSessionTerminationReason, options: CallTerminationOptions) + + fileprivate init(_ context: CallSessionContext) { + switch context.state { + case .ringing: + self = .ringing + case .accepting, .awaitingConfirmation: + self = .accepting + case .requesting: + self = .requesting(ringing: false) + case .confirming: + self = .requesting(ringing: true) + case let .requested(_, _, _, _, _, remoteConfirmationTimestamp): + self = .requesting(ringing: remoteConfirmationTimestamp != nil) + case let .active(id, accessHash, _, key, _, keyVisualHash, connections, maxLayer, allowsP2P): + self = .active(id: CallId(id: id, accessHash: accessHash), key: key, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, allowsP2P: allowsP2P) + case .dropping: + self = .dropping + case let .terminated(id, accessHash, reason, reportRating, sendDebugLogs): + var options = CallTerminationOptions() + if reportRating { + options.insert(.reportRating) + } + if sendDebugLogs { + options.insert(.sendDebugLogs) + } + let callId: CallId? + if let id = id, let accessHash = accessHash { + callId = CallId(id: id, accessHash: accessHash) + } else { + callId = nil + } + self = .terminated(id: callId, reason: reason, options: options) + } + } +} + +public struct CallSession { + public let id: CallSessionInternalId + public let isOutgoing: Bool + public let state: CallSessionState +} + +public struct CallSessionConnection { + public let id: Int64 + public let ip: String + public let ipv6: String + public let port: Int32 + public let peerTag: Data +} + +private func parseConnection(_ apiConnection: Api.PhoneConnection) -> CallSessionConnection { + switch apiConnection { + case let .phoneConnection(id, ip, ipv6, port, peerTag): + return CallSessionConnection(id: id, ip: ip, ipv6: ipv6, port: port, peerTag: peerTag.makeData()) + } +} + +public struct CallSessionConnectionSet { + public let primary: CallSessionConnection + public let alternatives: [CallSessionConnection] +} + +private func parseConnectionSet(primary: Api.PhoneConnection, alternative: [Api.PhoneConnection]) -> CallSessionConnectionSet { + return CallSessionConnectionSet(primary: parseConnection(primary), alternatives: alternative.map { parseConnection($0) }) +} + +private final class CallSessionContext { + let peerId: PeerId + let isOutgoing: Bool + var state: CallSessionInternalState + let subscribers = Bag<(CallSession) -> Void>() + + let acknowledgeIncomingCallDisposable = MetaDisposable() + + var isEmpty: Bool { + if case .terminated = self.state { + return self.subscribers.isEmpty + } else { + return false + } + } + + init(peerId: PeerId, isOutgoing: Bool, state: CallSessionInternalState) { + self.peerId = peerId + self.isOutgoing = isOutgoing + self.state = state + } + + deinit { + self.acknowledgeIncomingCallDisposable.dispose() + } +} + +private final class CallSessionManagerContext { + private let queue: Queue + private let postbox: Postbox + private let network: Network + private let maxLayer: Int32 + private let addUpdates: (Api.Updates) -> Void + + private let ringingSubscribers = Bag<([CallSessionRingingState]) -> Void>() + private var contexts: [CallSessionInternalId: CallSessionContext] = [:] + private var contextIdByStableId: [CallSessionStableId: CallSessionInternalId] = [:] + + private let disposables = DisposableSet() + + init(queue: Queue, postbox: Postbox, network: Network, maxLayer: Int32, addUpdates: @escaping (Api.Updates) -> Void) { + self.queue = queue + self.postbox = postbox + self.network = network + self.maxLayer = maxLayer + self.addUpdates = addUpdates + } + + deinit { + assert(self.queue.isCurrent()) + self.disposables.dispose() + } + + func ringingStates() -> Signal<[CallSessionRingingState], NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let index = strongSelf.ringingSubscribers.add { next in + subscriber.putNext(next) + } + subscriber.putNext(strongSelf.ringingStatesValue()) + disposable.set(ActionDisposable { + queue.async { + if let strongSelf = self { + strongSelf.ringingSubscribers.remove(index) + } + } + }) + } + } + return disposable + } + } + + func callState(internalId: CallSessionInternalId) -> Signal { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self, let context = strongSelf.contexts[internalId] { + let index = context.subscribers.add { next in + subscriber.putNext(next) + } + subscriber.putNext(CallSession(id: internalId, isOutgoing: context.isOutgoing, state: CallSessionState(context))) + disposable.set(ActionDisposable { + queue.async { + if let strongSelf = self, let context = strongSelf.contexts[internalId] { + context.subscribers.remove(index) + if context.isEmpty { + strongSelf.contexts.removeValue(forKey: internalId) + } + } + } + }) + } + } + return disposable + } + } + + private func ringingStatesValue() -> [CallSessionRingingState] { + var ringingContexts: [CallSessionRingingState] = [] + for (id, context) in self.contexts { + if case .ringing = context.state { + ringingContexts.append(CallSessionRingingState(id: id, peerId: context.peerId)) + } + } + return ringingContexts + } + + private func ringingStatesUpdated() { + let states = self.ringingStatesValue() + for subscriber in self.ringingSubscribers.copyItems() { + subscriber(states) + } + } + + private func contextUpdated(internalId: CallSessionInternalId) { + if let context = self.contexts[internalId] { + let session = CallSession(id: internalId, isOutgoing: context.isOutgoing, state: CallSessionState(context)) + for subscriber in context.subscribers.copyItems() { + subscriber(session) + } + } + } + + private func addIncoming(peerId: PeerId, stableId: CallSessionStableId, accessHash: Int64, timestamp: Int32, gAHash: Data) { + if self.contextIdByStableId[stableId] != nil { + return + } + + let bBytes = malloc(256)! + let randomStatus = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self)) + let b = Data(bytesNoCopy: bBytes, count: 256, deallocator: .free) + + if randomStatus == 0 { + let internalId = CallSessionInternalId() + let context = CallSessionContext(peerId: peerId, isOutgoing: false, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b)) + self.contexts[internalId] = context + context.acknowledgeIncomingCallDisposable.set(self.network.request(Api.functions.phone.receivedCall(peer: .inputPhoneCall(id: stableId, accessHash: accessHash))).start()) + self.contextIdByStableId[stableId] = internalId + self.contextUpdated(internalId: internalId) + self.ringingStatesUpdated() + } + } + + func drop(internalId: CallSessionInternalId, reason: DropCallReason) { + if let context = self.contexts[internalId] { + var dropData: (CallSessionStableId, Int64, DropCallSessionReason)? + var wasRinging = false + switch context.state { + case let .ringing(id, accessHash, _, _): + wasRinging = true + let internalReason: DropCallSessionReason + switch reason { + case .busy, .hangUp: + internalReason = .hangUp(0) + case .disconnect: + internalReason = .disconnect + case .missed: + internalReason = .missed + } + dropData = (id, accessHash, internalReason) + case let .accepting(id, accessHash, _, _, disposable): + dropData = (id, accessHash, .abort) + disposable.dispose() + case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _): + let duration = max(0, Int32(CFAbsoluteTimeGetCurrent()) - beginTimestamp) + let internalReason: DropCallSessionReason + switch reason { + case .busy, .hangUp: + internalReason = .hangUp(duration) + case .disconnect: + internalReason = .disconnect + case .missed: + internalReason = .missed + } + dropData = (id, accessHash, internalReason) + case .dropping, .terminated: + break + case let .awaitingConfirmation(id, accessHash, _, _, _): + dropData = (id, accessHash, .abort) + case let .confirming(id, accessHash, _, _, _, disposable): + disposable.dispose() + dropData = (id, accessHash, .abort) + case let .requested(id, accessHash, _, _, _, _): + let internalReason: DropCallSessionReason + switch reason { + case .busy, .hangUp: + internalReason = .missed + case .disconnect: + internalReason = .disconnect + case .missed: + internalReason = .missed + } + dropData = (id, accessHash, internalReason) + case let .requesting(_, disposable): + disposable.dispose() + context.state = .terminated(id: nil, accessHash: nil, reason: .ended(.hungUp), reportRating: false, sendDebugLogs: false) + self.contextUpdated(internalId: internalId) + if context.isEmpty { + self.contexts.removeValue(forKey: internalId) + } + } + + if let (id, accessHash, reason) = dropData { + self.contextIdByStableId.removeValue(forKey: id) + context.state = .dropping((dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, reason: reason) |> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in + if let strongSelf = self { + if let context = strongSelf.contexts[internalId] { + context.state = .terminated(id: id, accessHash: accessHash, reason: .ended(.hungUp), reportRating: reportRating, sendDebugLogs: sendDebugLogs) + strongSelf.contextUpdated(internalId: internalId) + if context.isEmpty { + strongSelf.contexts.removeValue(forKey: internalId) + } + } + } + })) + self.contextUpdated(internalId: internalId) + if wasRinging { + self.ringingStatesUpdated() + } + } + } + } + + func drop(stableId: CallSessionStableId, reason: DropCallReason) { + if let internalId = self.contextIdByStableId[stableId] { + self.contextIdByStableId.removeValue(forKey: stableId) + self.drop(internalId: internalId, reason: reason) + } + } + + func dropAll() { + let contexts = self.contexts + for (internalId, _) in contexts { + self.drop(internalId: internalId, reason: .hangUp) + } + } + + func accept(internalId: CallSessionInternalId) { + if let context = self.contexts[internalId] { + switch context.state { + case let .ringing(id, accessHash, gAHash, b): + context.state = .accepting(id: id, accessHash: accessHash, gAHash: gAHash, b: b, disposable: (acceptCallSession(postbox: self.postbox, network: self.network, stableId: id, accessHash: accessHash, b: b, maxLayer: self.maxLayer) |> deliverOn(self.queue)).start(next: { [weak self] result in + if let strongSelf = self, let context = strongSelf.contexts[internalId] { + if case .accepting = context.state { + switch result { + case .failed: + strongSelf.drop(internalId: internalId, reason: .disconnect) + case let .success(call): + switch call { + case let .waiting(config): + context.state = .awaitingConfirmation(id: id, accessHash: accessHash, gAHash: gAHash, b: b, config: config) + strongSelf.contextUpdated(internalId: internalId) + case let .call(config, gA, timestamp, connections, maxLayer, allowsP2P): + if let (key, keyId, keyVisualHash) = strongSelf.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gA) { + context.state = .active(id: id, accessHash: accessHash, beginTimestamp: timestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, allowsP2P: allowsP2P) + strongSelf.contextUpdated(internalId: internalId) + } else { + strongSelf.drop(internalId: internalId, reason: .disconnect) + } + } + } + } + } + })) + self.contextUpdated(internalId: internalId) + self.ringingStatesUpdated() + default: + break + } + } + } + + func updateSession(_ call: Api.PhoneCall) { + switch call { + case .phoneCallEmpty: + break + case let .phoneCallAccepted(flags, id, _, _, _, _, gB, _): + if let internalId = self.contextIdByStableId[id] { + if let context = self.contexts[internalId] { + switch context.state { + case let .requested(_, accessHash, a, gA, config, _): + let p = config.p.makeData() + if !MTCheckIsSafeGAOrB(gA, p) { + self.drop(internalId: internalId, reason: .disconnect) + } + var key = MTExp(gB.makeData(), a, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyId: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8) + } + + let keyVisualHash = MTSha256(key + gA)! + + context.state = .confirming(id: id, accessHash: accessHash, key: key, keyId: keyId, keyVisualHash: keyVisualHash, disposable: (confirmCallSession(network: self.network, stableId: id, accessHash: accessHash, gA: gA, keyFingerprint: keyId, maxLayer: self.maxLayer) |> deliverOnMainQueue).start(next: { [weak self] updatedCall in + if let strongSelf = self, let context = strongSelf.contexts[internalId], case .confirming = context.state { + if let updatedCall = updatedCall { + strongSelf.updateSession(updatedCall) + } else { + strongSelf.drop(internalId: internalId, reason: .disconnect) + } + } + })) + self.contextUpdated(internalId: internalId) + default: + self.drop(internalId: internalId, reason: .disconnect) + } + } else { + assertionFailure() + } + } + case let .phoneCallDiscarded(flags, id, reason, _): + let reportRating = (flags & (1 << 2)) != 0 + let sendDebugLogs = (flags & (1 << 3)) != 0 + if let internalId = self.contextIdByStableId[id] { + if let context = self.contexts[internalId] { + let parsedReason: CallSessionTerminationReason + if let reason = reason { + switch reason { + case .phoneCallDiscardReasonBusy: + parsedReason = .ended(.busy) + case .phoneCallDiscardReasonDisconnect: + parsedReason = .error(.disconnected) + case .phoneCallDiscardReasonHangup: + parsedReason = .ended(.hungUp) + case .phoneCallDiscardReasonMissed: + parsedReason = .ended(.missed) + } + } else { + parsedReason = .ended(.hungUp) + } + + switch context.state { + case let .accepting(id, accessHash, _, _, disposable): + disposable.dispose() + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.contextUpdated(internalId: internalId) + case let .active(id, accessHash, _, _, _, _, _, _, _): + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.contextUpdated(internalId: internalId) + case let .awaitingConfirmation(id, accessHash, _, _, _): + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.contextUpdated(internalId: internalId) + case let .requested(id, accessHash, _, _, _, _): + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.contextUpdated(internalId: internalId) + case let .confirming(id, accessHash, _, _, _, disposable): + disposable.dispose() + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.contextUpdated(internalId: internalId) + case let .requesting(_, disposable): + disposable.dispose() + context.state = .terminated(id: nil, accessHash: nil, reason: parsedReason, reportRating: false, sendDebugLogs: false) + self.contextUpdated(internalId: internalId) + case let .ringing(id, accessHash, _, _): + context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs) + self.ringingStatesUpdated() + self.contextUpdated(internalId: internalId) + case .dropping, .terminated: + break + } + } else { + //assertionFailure() + } + } + case let .phoneCall(flags, id, _, _, _, _, gAOrB, keyFingerprint, callProtocol, connections, startDate): + let allowsP2P = (flags & (1 << 5)) != 0 + if let internalId = self.contextIdByStableId[id] { + if let context = self.contexts[internalId] { + switch context.state { + case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested: + break + case let .awaitingConfirmation(_, accessHash, gAHash, b, config): + if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) { + if keyFingerprint == calculatedKeyId { + switch callProtocol { + case let .phoneCallProtocol(_, _, maxLayer): + context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, allowsP2P: allowsP2P) + self.contextUpdated(internalId: internalId) + } + } else { + self.drop(internalId: internalId, reason: .disconnect) + } + } else { + self.drop(internalId: internalId, reason: .disconnect) + } + case let .confirming(id, accessHash, key, keyId, keyVisualHash, _): + switch callProtocol { + case let .phoneCallProtocol(_, _, maxLayer): + context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, allowsP2P: allowsP2P) + self.contextUpdated(internalId: internalId) + } + } + } else { + assertionFailure() + } + } + case let .phoneCallRequested(flags, id, accessHash, date, adminId, _, gAHash, _): + if self.contextIdByStableId[id] == nil { + self.addIncoming(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId), stableId: id, accessHash: accessHash, timestamp: date, gAHash: gAHash.makeData()) + } + case let .phoneCallWaiting(_, id, _, _, _, _, _, receiveDate): + if let internalId = self.contextIdByStableId[id] { + if let context = self.contexts[internalId] { + switch context.state { + case let .requested(id, accessHash, a, gA, config, remoteConfirmationTimestamp): + if let receiveDate = receiveDate, remoteConfirmationTimestamp == nil { + context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: receiveDate) + self.contextUpdated(internalId: internalId) + } + default: + break + } + } else { + assertionFailure() + } + } + } + } + + private func makeSessionEncryptionKey(config: SecretChatEncryptionConfig, gAHash: Data, b: Data, gA: Data) -> (key: Data, keyId: Int64, keyVisualHash: Data)? { + var key = MTExp(gA, b, config.p.makeData())! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyId: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8) + } + + if MTSha256(gA)! != gAHash { + return nil + } + + let keyVisualHash = MTSha256(key + gA)! + + return (key, keyId, keyVisualHash) + } + + func request(peerId: PeerId, internalId: CallSessionInternalId) -> CallSessionInternalId? { + let aBytes = malloc(256)! + let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self)) + let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free) + if randomStatus == 0 { + self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, state: .requesting(a: a, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer) |> deliverOn(queue)).start(next: { [weak self] result in + if let strongSelf = self, let context = strongSelf.contexts[internalId] { + if case .requesting = context.state { + switch result { + case let .success(id, accessHash, config, gA, remoteConfirmationTimestamp): + context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: remoteConfirmationTimestamp) + strongSelf.contextIdByStableId[id] = internalId + strongSelf.contextUpdated(internalId: internalId) + case let .failed(error): + context.state = .terminated(id: nil, accessHash: nil, reason: .error(error), reportRating: false, sendDebugLogs: false) + strongSelf.contextUpdated(internalId: internalId) + if context.isEmpty { + strongSelf.contexts.removeValue(forKey: internalId) + } + } + } + } + }))) + self.contextUpdated(internalId: internalId) + return internalId + } else { + return nil + } + } +} + +public enum CallRequestError { + case generic +} + +public final class CallSessionManager { + private let queue = Queue() + private var contextRef: Unmanaged? + + init(postbox: Postbox, network: Network, maxLayer: Int32, addUpdates: @escaping (Api.Updates) -> Void) { + self.queue.async { + let context = CallSessionManagerContext(queue: self.queue, postbox: postbox, network: network, maxLayer: maxLayer, addUpdates: addUpdates) + self.contextRef = Unmanaged.passRetained(context) + } + } + + deinit { + let contextRef = self.contextRef + self.queue.async { + contextRef?.release() + } + } + + private func withContext(_ f: @escaping (CallSessionManagerContext) -> Void) { + self.queue.async { + if let contextRef = self.contextRef { + let context = contextRef.takeUnretainedValue() + f(context) + } + } + } + + func updateSession(_ call: Api.PhoneCall) { + self.withContext { context in + context.updateSession(call) + } + } + + public func drop(internalId: CallSessionInternalId, reason: DropCallReason) { + self.withContext { context in + context.drop(internalId: internalId, reason: reason) + } + } + + func drop(stableId: CallSessionStableId, reason: DropCallReason) { + self.withContext { context in + context.drop(stableId: stableId, reason: reason) + } + } + + func dropAll() { + self.withContext { context in + context.dropAll() + } + } + + public func accept(internalId: CallSessionInternalId) { + self.withContext { context in + context.accept(internalId: internalId) + } + } + + public func request(peerId: PeerId, internalId: CallSessionInternalId = CallSessionInternalId()) -> Signal { + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + + self?.withContext { context in + if let internalId = context.request(peerId: peerId, internalId: internalId) { + subscriber.putNext(internalId) + subscriber.putCompletion() + } + } + + return disposable + } + } + + public func ringingStates() -> Signal<[CallSessionRingingState], NoError> { + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + self?.withContext { context in + disposable.set(context.ringingStates().start(next: { next in + subscriber.putNext(next) + })) + } + return disposable + } + } + + public func callState(internalId: CallSessionInternalId) -> Signal { + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + self?.withContext { context in + disposable.set(context.callState(internalId: internalId).start(next: { next in + subscriber.putNext(next) + })) + } + return disposable + } + } +} + +private enum AcceptedCall { + case waiting(config: SecretChatEncryptionConfig) + case call(config: SecretChatEncryptionConfig, gA: Data, timestamp: Int32, connections: CallSessionConnectionSet, maxLayer: Int32, allowsP2P: Bool) +} + +private enum AcceptCallResult { + case failed + case success(AcceptedCall) +} + +private func acceptCallSession(postbox: Postbox, network: Network, stableId: CallSessionStableId, accessHash: Int64, b: Data, maxLayer: Int32) -> Signal { + return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let bData = b + + let gb = MTExp(g, bData, p)! + + if !MTCheckIsSafeGAOrB(gb, p) { + return .single(.failed) + } + + return network.request(Api.functions.phone.acceptCall(peer: .inputPhoneCall(id: stableId, accessHash: accessHash), gB: Buffer(data: gb), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: minLayer, maxLayer: maxLayer))) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { call -> Signal in + if let call = call { + return postbox.transaction { transaction -> AcceptCallResult in + switch call { + case let .phoneCall(phoneCall, users): + var parsedUsers: [Peer] = [] + for user in users { + parsedUsers.append(TelegramUser(user: user)) + } + updatePeers(transaction: transaction, peers: parsedUsers, update: { _, updated in + return updated + }) + + switch phoneCall { + case .phoneCallEmpty, .phoneCallRequested, .phoneCallAccepted, .phoneCallDiscarded: + return .failed + case .phoneCallWaiting: + return .success(.waiting(config: config)) + case let .phoneCall(flags, id, _, _, _, _, gAOrB, _, callProtocol, connections, startDate): + if id == stableId { + switch callProtocol{ + case let .phoneCallProtocol(_, _, maxLayer): + return .success(.call(config: config, gA: gAOrB.makeData(), timestamp: startDate, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, allowsP2P: (flags & (1 << 5)) != 0)) + } + } else { + return .failed + } + } + } + } + } else { + return .single(.failed) + } + } + } +} + +private enum RequestCallSessionResult { + case success(id: CallSessionStableId, accessHash: Int64, config: SecretChatEncryptionConfig, gA: Data, remoteConfirmationTimestamp: Int32?) + case failed(CallSessionError) +} + +private func requestCallSession(postbox: Postbox, network: Network, peerId: PeerId, a: Data, maxLayer: Int32) -> Signal { + return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + return postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let ga = MTExp(g, a, p)! + if !MTCheckIsSafeGAOrB(ga, p) { + return .single(.failed(.generic)) + } + + let gAHash = MTSha256(ga)! + + return network.request(Api.functions.phone.requestCall(flags: 0, userId: inputUser, randomId: Int32(bitPattern: arc4random()), gAHash: Buffer(data: gAHash), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: minLayer, maxLayer: maxLayer))) + |> map { result -> RequestCallSessionResult in + switch result { + case let .phoneCall(phoneCall, _): + switch phoneCall { + case let .phoneCallRequested(flags, id, accessHash, _, _, _, _, _): + return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: nil) + case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate): + return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: receiveDate) + default: + return .failed(.generic) + } + } + } + |> `catch` { error -> Signal in + switch error.errorDescription { + case "PARTICIPANT_VERSION_OUTDATED": + return .single(.failed(.notSupportedByPeer)) + case "USER_PRIVACY_RESTRICTED": + return .single(.failed(.privacyRestricted)) + default: + if error.errorCode == 406 { + return .single(.failed(.serverProvided(error.errorDescription))) + } else { + return .single(.failed(.generic)) + } + } + } + } else { + return .single(.failed(.generic)) + } + } + |> switchToLatest + } +} + +private func confirmCallSession(network: Network, stableId: CallSessionStableId, accessHash: Int64, gA: Data, keyFingerprint: Int64, maxLayer: Int32) -> Signal { + return network.request(Api.functions.phone.confirmCall(peer: Api.InputPhoneCall.inputPhoneCall(id: stableId, accessHash: accessHash), gA: Buffer(data: gA), keyFingerprint: keyFingerprint, protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: minLayer, maxLayer: maxLayer))) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> Api.PhoneCall? in + if let result = result { + switch result { + case let .phoneCall(phoneCall, _): + return phoneCall + } + } else { + return nil + } + } +} + +private enum DropCallSessionReason { + case abort + case hangUp(Int32) + case busy + case disconnect + case missed +} + +private func dropCallSession(network: Network, addUpdates: @escaping (Api.Updates) -> Void, stableId: CallSessionStableId, accessHash: Int64, reason: DropCallSessionReason) -> Signal<(Bool, Bool), NoError> { + var mappedReason: Api.PhoneCallDiscardReason + var duration: Int32 = 0 + switch reason { + case .abort: + mappedReason = .phoneCallDiscardReasonHangup + case let .hangUp(value): + duration = value + mappedReason = .phoneCallDiscardReasonHangup + case .busy: + mappedReason = .phoneCallDiscardReasonBusy + case .disconnect: + mappedReason = .phoneCallDiscardReasonDisconnect + case .missed: + mappedReason = .phoneCallDiscardReasonMissed + } + return network.request(Api.functions.phone.discardCall(flags: 0, peer: Api.InputPhoneCall.inputPhoneCall(id: stableId, accessHash: accessHash), duration: duration, reason: mappedReason, connectionId: 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal<(Bool, Bool), NoError> in + var reportRating: Bool = false + var sendDebugLogs: Bool = false + if let updates = updates { + switch updates { + case .updates(let updates, _, _, _, _): + for update in updates { + switch update { + case .updatePhoneCall(let phoneCall): + switch phoneCall { + case.phoneCallDiscarded(let values): + reportRating = (values.flags & (1 << 2)) != 0 + sendDebugLogs = (values.flags & (1 << 3)) != 0 + default: + break + } + break + default: + break + } + } + default: + break + } + + addUpdates(updates) + + } + return .single((reportRating, sendDebugLogs)) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CanSendMessagesToPeer.swift b/submodules/TelegramCore/TelegramCore/CanSendMessagesToPeer.swift new file mode 100644 index 0000000000..a472b83596 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CanSendMessagesToPeer.swift @@ -0,0 +1,18 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public func canSendMessagesToPeer(_ peer: Peer) -> Bool { + if peer is TelegramUser || peer is TelegramGroup { + return !peer.isDeleted + } else if let peer = peer as? TelegramSecretChat { + return peer.embeddedState == .active + } else if let peer = peer as? TelegramChannel { + return peer.hasPermission(.sendMessages) + } else { + return false + } +} diff --git a/submodules/TelegramCore/TelegramCore/CancelAccountReset.swift b/submodules/TelegramCore/TelegramCore/CancelAccountReset.swift new file mode 100644 index 0000000000..15ee33526c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CancelAccountReset.swift @@ -0,0 +1,91 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct CancelAccountResetData: Equatable { + public let type: SentAuthorizationCodeType + public let hash: String + public let timeout: Int32? + public let nextType: AuthorizationCodeNextType? +} + +public enum RequestCancelAccountResetDataError { + case limitExceeded + case generic +} + +public func requestCancelAccountResetData(network: Network, hash: String) -> Signal { + return network.request(Api.functions.account.sendConfirmPhoneCode(flags: 0, hash: hash, currentNumber: nil), automaticFloodWait: false) + |> mapError { error -> RequestCancelAccountResetDataError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else { + return .generic + } + } + |> map { sentCode -> CancelAccountResetData in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, _): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + return CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType) + } + } +} + +public func requestNextCancelAccountResetOption(network: Network, phoneNumber: String, phoneCodeHash: String) -> Signal { + return network.request(Api.functions.auth.resendCode(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), automaticFloodWait: false) + |> mapError { error -> RequestCancelAccountResetDataError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else { + return .generic + } + } + |> map { sentCode -> CancelAccountResetData in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, _): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + return CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType) + } + } +} + +public enum CancelAccountResetError { + case generic + case invalidCode + case codeExpired + case limitExceeded +} + +public func requestCancelAccountReset(network: Network, phoneCodeHash: String, phoneCode: String) -> Signal { + return network.request(Api.functions.account.confirmPhone(phoneCodeHash: phoneCodeHash, phoneCode: phoneCode)) + |> mapError { error -> CancelAccountResetError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_CODE_INVALID" { + return .invalidCode + } else if error.errorDescription == "PHONE_CODE_EXPIRED" { + return .codeExpired + } else { + return .generic + } + } + |> ignoreValues +} diff --git a/submodules/TelegramCore/TelegramCore/ChangeAccountPhoneNumber.swift b/submodules/TelegramCore/TelegramCore/ChangeAccountPhoneNumber.swift new file mode 100644 index 0000000000..e613286390 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChangeAccountPhoneNumber.swift @@ -0,0 +1,124 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct ChangeAccountPhoneNumberData: Equatable { + public let type: SentAuthorizationCodeType + public let hash: String + public let timeout: Int32? + public let nextType: AuthorizationCodeNextType? + + public static func ==(lhs: ChangeAccountPhoneNumberData, rhs: ChangeAccountPhoneNumberData) -> Bool { + if lhs.type != rhs.type { + return false + } + if lhs.hash != rhs.hash { + return false + } + if lhs.timeout != rhs.timeout { + return false + } + if lhs.nextType != rhs.nextType { + return false + } + return true + } +} + +public enum RequestChangeAccountPhoneNumberVerificationError { + case invalidPhoneNumber + case limitExceeded + case phoneNumberOccupied + case generic +} + +public func requestChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String) -> Signal { + return account.network.request(Api.functions.account.sendChangePhoneCode(flags: 0, phoneNumber: phoneNumber, currentNumber: nil), automaticFloodWait: false) + |> mapError { error -> RequestChangeAccountPhoneNumberVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_NUMBER_INVALID" { + return .invalidPhoneNumber + } else if error.errorDescription == "PHONE_NUMBER_OCCUPIED" { + return .phoneNumberOccupied + } else { + return .generic + } + } + |> map { sentCode -> ChangeAccountPhoneNumberData in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, _): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + return ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType) + } + } +} + +public func requestNextChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, phoneCodeHash: String) -> Signal { + return account.network.request(Api.functions.auth.resendCode(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), automaticFloodWait: false) + |> mapError { error -> RequestChangeAccountPhoneNumberVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_NUMBER_INVALID" { + return .invalidPhoneNumber + } else if error.errorDescription == "PHONE_NUMBER_OCCUPIED" { + return .phoneNumberOccupied + } else { + return .generic + } + } + |> map { sentCode -> ChangeAccountPhoneNumberData in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, _): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + return ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType) + } + } +} + +public enum ChangeAccountPhoneNumberError { + case generic + case invalidCode + case codeExpired + case limitExceeded +} + +public func requestChangeAccountPhoneNumber(account: Account, phoneNumber: String, phoneCodeHash: String, phoneCode: String) -> Signal { + return account.network.request(Api.functions.account.changePhone(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, phoneCode: phoneCode), automaticFloodWait: false) + |> mapError { error -> ChangeAccountPhoneNumberError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PHONE_CODE_INVALID" { + return .invalidCode + } else if error.errorDescription == "PHONE_CODE_EXPIRED" { + return .codeExpired + } else { + return .generic + } + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + let user = TelegramUser(user: result) + updatePeers(transaction: transaction, peers: [user], update: { _, updated in + return updated + }) + } |> mapError { _ -> ChangeAccountPhoneNumberError in return .generic } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChangePeerNotificationSettings.swift b/submodules/TelegramCore/TelegramCore/ChangePeerNotificationSettings.swift new file mode 100644 index 0000000000..42f3137f0e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChangePeerNotificationSettings.swift @@ -0,0 +1,131 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func togglePeerMuted(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Void in + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + let updatedSettings: TelegramPeerNotificationSettings + switch previousSettings.muteState { + case .unmuted, .default: + updatedSettings = previousSettings.withUpdatedMuteState(.muted(until: Int32.max)) + case .muted: + updatedSettings = previousSettings.withUpdatedMuteState(.default) + } + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } + } +} + +public func updatePeerMuteSetting(account: Account, peerId: PeerId, muteInterval: Int32?) -> Signal { + return account.postbox.transaction { transaction -> Void in + updatePeerMuteSetting(transaction: transaction, peerId: peerId, muteInterval: muteInterval) + } +} + +public func updatePeerMuteSetting(transaction: Transaction, peerId: PeerId, muteInterval: Int32?) { + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + let muteState: PeerMuteState + if let muteInterval = muteInterval { + if muteInterval == 0 { + muteState = .unmuted + } else { + let absoluteUntil: Int32 + if muteInterval == Int32.max { + absoluteUntil = Int32.max + } else { + absoluteUntil = Int32(Date().timeIntervalSince1970) + muteInterval + } + muteState = .muted(until: absoluteUntil) + } + } else { + muteState = .default + } + + let updatedSettings = previousSettings.withUpdatedMuteState(muteState) + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } +} + +public func updatePeerDisplayPreviewsSetting(account: Account, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) -> Signal { + return account.postbox.transaction { transaction -> Void in + updatePeerDisplayPreviewsSetting(transaction: transaction, peerId: peerId, displayPreviews: displayPreviews) + } +} + +public func updatePeerDisplayPreviewsSetting(transaction: Transaction, peerId: PeerId, displayPreviews: PeerNotificationDisplayPreviews) { + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + let updatedSettings = previousSettings.withUpdatedDisplayPreviews(displayPreviews) + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } +} + +public func updatePeerNotificationSoundInteractive(account: Account, peerId: PeerId, sound: PeerMessageSound) -> Signal { + return account.postbox.transaction { transaction -> Void in + updatePeerNotificationSoundInteractive(transaction: transaction, peerId: peerId, sound: sound) + } +} + +public func updatePeerNotificationSoundInteractive(transaction: Transaction, peerId: PeerId, sound: PeerMessageSound) { + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + let currentSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings + let previousSettings: TelegramPeerNotificationSettings + if let currentSettings = currentSettings { + previousSettings = currentSettings + } else { + previousSettings = TelegramPeerNotificationSettings.defaultSettings + } + + let updatedSettings = previousSettings.withUpdatedMessageSound(sound) + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: updatedSettings) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogContext.swift b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogContext.swift new file mode 100644 index 0000000000..08a91cf544 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogContext.swift @@ -0,0 +1,217 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct ChannelAdminEventLogEntry: Comparable { + public let stableId: UInt32 + public let event: AdminLogEvent + public let peers: [PeerId: Peer] + + public static func ==(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool { + return lhs.event == rhs.event + } + + public static func <(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool { + return lhs.event < rhs.event + } +} + +public enum ChannelAdminEventLogUpdateType { + case initial + case generic + case load +} + +public struct ChannelAdminEventLogFilter: Equatable { + public let query: String? + public let events: AdminLogEventsFlags + public let adminPeerIds: [PeerId]? + + public init(query: String? = nil, events: AdminLogEventsFlags = .all, adminPeerIds: [PeerId]? = nil) { + self.query = query + self.events = events + self.adminPeerIds = adminPeerIds + } + + public static func ==(lhs: ChannelAdminEventLogFilter, rhs: ChannelAdminEventLogFilter) -> Bool { + if lhs.query != rhs.query { + return false + } + if lhs.events != rhs.events { + return false + } + if let lhsAdminPeerIds = lhs.adminPeerIds, let rhsAdminPeerIds = rhs.adminPeerIds { + if lhsAdminPeerIds != rhsAdminPeerIds { + return false + } + } else if (lhs.adminPeerIds != nil) != (rhs.adminPeerIds != nil) { + return false + } + return true + } + + public var isEmpty: Bool { + if self.query != nil { + return false + } + if self.events != .all { + return false + } + if self.adminPeerIds != nil { + return false + } + return true + } + + public func withQuery(_ query: String?) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: query, events: self.events, adminPeerIds: self.adminPeerIds) + } + + public func withEvents(_ events: AdminLogEventsFlags) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: self.query, events: events, adminPeerIds: self.adminPeerIds) + } + + public func withAdminPeerIds(_ adminPeerIds: [PeerId]?) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: self.query, events: self.events, adminPeerIds: adminPeerIds) + } +} + +public final class ChannelAdminEventLogContext { + private let queue: Queue = Queue.mainQueue() + + private let postbox: Postbox + private let network: Network + private let peerId: PeerId + + private var filter: ChannelAdminEventLogFilter = ChannelAdminEventLogFilter() + + private var nextStableId: UInt32 = 1 + private var stableIds: [AdminLogEventId: UInt32] = [:] + + private var entries: ([ChannelAdminEventLogEntry], ChannelAdminEventLogFilter) = ([], ChannelAdminEventLogFilter()) + private var hasEntries: Bool = false + private var hasEarlier: Bool = true + private var loadingMoreEarlier: Bool = false + + private var subscribers = Bag<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType, Bool) -> Void>() + + private let loadMoreDisposable = MetaDisposable() + + public init(postbox: Postbox, network: Network, peerId: PeerId) { + self.postbox = postbox + self.network = network + self.peerId = peerId + } + + deinit { + self.loadMoreDisposable.dispose() + } + + public func get() -> Signal<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType, Bool), NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + if let strongSelf = self { + subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, .initial, strongSelf.hasEntries)) + + let index = strongSelf.subscribers.add({ entries, hasEarlier, type, hasEntries in + subscriber.putNext((entries, hasEarlier, type, hasEntries)) + }) + + return ActionDisposable { + queue.async { + if let strongSelf = self { + strongSelf.subscribers.remove(index) + } + } + } + } else { + return EmptyDisposable + } + } |> runOn(queue) + } + + public func setFilter(_ filter: ChannelAdminEventLogFilter) { + if self.filter != filter { + self.filter = filter + self.loadingMoreEarlier = false + self.hasEarlier = false + self.hasEntries = false + + for subscriber in self.subscribers.copyItems() { + subscriber(self.entries.0, self.hasEarlier, .load, self.hasEntries) + } + + self.loadMoreEntries() + } + } + + public func loadMoreEntries() { + assert(self.queue.isCurrent()) + + if self.loadingMoreEarlier { + return + } + + let maxId: AdminLogEventId + if self.entries.1 == self.filter, let first = self.entries.0.first { + maxId = first.event.id + } else { + maxId = AdminLogEventId.max + } + + self.loadingMoreEarlier = true + self.loadMoreDisposable.set((channelAdminLogEvents(postbox: self.postbox, network: self.network, peerId: self.peerId, maxId: maxId, minId: AdminLogEventId.min, limit: 100, query: self.filter.query, filter: self.filter.events, admins: self.filter.adminPeerIds) + |> deliverOn(self.queue)).start(next: { [weak self] result in + if let strongSelf = self { + var events = result.events.sorted() + if strongSelf.entries.1 == strongSelf.filter { + if let first = strongSelf.entries.0.first { + var clipIndex = events.count + for i in (0 ..< events.count).reversed() { + if events[i] >= first.event { + clipIndex = i - 1 + } + } + if clipIndex < events.count { + events.removeSubrange(clipIndex ..< events.count) + } + } + + var entries: [ChannelAdminEventLogEntry] = events.map { event in + return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers) + } + entries.append(contentsOf: strongSelf.entries.0) + strongSelf.entries = (entries, strongSelf.filter) + } else { + let entries: [ChannelAdminEventLogEntry] = events.map { event in + return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers) + } + strongSelf.entries = (entries, strongSelf.filter) + } + + strongSelf.hasEarlier = !events.isEmpty + strongSelf.loadingMoreEarlier = false + strongSelf.hasEntries = true + + for subscriber in strongSelf.subscribers.copyItems() { + subscriber(strongSelf.entries.0, strongSelf.hasEarlier, .load, strongSelf.hasEntries) + } + } + })) + } + + private func stableIdForEventId(_ id: AdminLogEventId) -> UInt32 { + if let value = self.stableIds[id] { + return value + } else { + let value = self.nextStableId + self.nextStableId += 1 + self.stableIds[id] = value + return value + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift new file mode 100644 index 0000000000..1efe8f3cee --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift @@ -0,0 +1,236 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public typealias AdminLogEventId = Int64 + +public struct AdminLogEvent: Comparable { + public let id: AdminLogEventId + public let peerId: PeerId + public let date: Int32 + public let action: AdminLogEventAction + + public static func ==(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool { + return lhs.id == rhs.id + } + + public static func <(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool { + if lhs.date != rhs.date { + return lhs.date < rhs.date + } else { + return lhs.id < rhs.id + } + } +} + +public struct AdminLogEventsResult { + public let peerId: PeerId + public let peers: [PeerId: Peer] + public let events: [AdminLogEvent] +} + +public enum AdminLogEventAction { + case changeTitle(prev: String, new: String) + case changeAbout(prev: String, new: String) + case changeUsername(prev: String, new: String) + case changePhoto(prev: [TelegramMediaImageRepresentation], new: [TelegramMediaImageRepresentation]) + case toggleInvites(Bool) + case toggleSignatures(Bool) + case updatePinned(Message?) + case editMessage(prev: Message, new: Message) + case deleteMessage(Message) + case participantJoin + case participantLeave + case participantInvite(RenderedChannelParticipant) + case participantToggleBan(prev: RenderedChannelParticipant, new: RenderedChannelParticipant) + case participantToggleAdmin(prev: RenderedChannelParticipant, new: RenderedChannelParticipant) + case changeStickerPack(prev: StickerPackReference?, new: StickerPackReference?) + case togglePreHistoryHidden(Bool) + case updateDefaultBannedRights(prev: TelegramChatBannedRights, new: TelegramChatBannedRights + ) + case pollStopped(Message) + case linkedPeerUpdated(previous: Peer?, updated: Peer?) +} + +public enum ChannelAdminLogEventError { + case generic +} + +public struct AdminLogEventsFlags: OptionSet { + public var rawValue: UInt32 + + public init(rawValue: UInt32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + public static let join = AdminLogEventsFlags(rawValue: 1 << 0) + public static let leave = AdminLogEventsFlags(rawValue: 1 << 1) + public static let invite = AdminLogEventsFlags(rawValue: 1 << 2) + public static let ban = AdminLogEventsFlags(rawValue: 1 << 3) + public static let unban = AdminLogEventsFlags(rawValue: 1 << 4) + public static let kick = AdminLogEventsFlags(rawValue: 1 << 5) + public static let unkick = AdminLogEventsFlags(rawValue: 1 << 6) + public static let promote = AdminLogEventsFlags(rawValue: 1 << 7) + public static let demote = AdminLogEventsFlags(rawValue: 1 << 8) + public static let info = AdminLogEventsFlags(rawValue: 1 << 9) + public static let settings = AdminLogEventsFlags(rawValue: 1 << 10) + public static let pinnedMessages = AdminLogEventsFlags(rawValue: 1 << 11) + public static let editMessages = AdminLogEventsFlags(rawValue: 1 << 12) + public static let deleteMessages = AdminLogEventsFlags(rawValue: 1 << 13) + + public static var all: AdminLogEventsFlags { + return [.join, .leave, .invite, .ban, .unban, .kick, .unkick, .promote, .demote, .info, .settings, .pinnedMessages, .editMessages, .deleteMessages] + } + public static var flags: AdminLogEventsFlags { + return [.join, .leave, .invite, .ban, .unban, .kick, .unkick, .promote, .demote, .info, .settings, .pinnedMessages, .editMessages, .deleteMessages] + } +} + +private func boolFromApiValue(_ value: Api.Bool) -> Bool { + switch value { + case .boolFalse: + return false + case .boolTrue: + return true + } +} + +public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, maxId: AdminLogEventId, minId: AdminLogEventId, limit: Int32 = 100, query: String? = nil, filter: AdminLogEventsFlags? = nil, admins: [PeerId]? = nil) -> Signal { + return postbox.transaction { transaction -> (Peer?, [Peer]?) in + return (transaction.getPeer(peerId), admins?.compactMap { transaction.getPeer($0) }) + } + |> introduceError(ChannelAdminLogEventError.self) + |> mapToSignal { (peer, admins) -> Signal in + if let peer = peer, let inputChannel = apiInputChannel(peer) { + let inputAdmins = admins?.compactMap { apiInputUser($0) } + + var flags: Int32 = 0 + var eventsFilter: Api.ChannelAdminLogEventsFilter? = nil + if let filter = filter { + flags += Int32(1 << 0) + eventsFilter = Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: Int32(filter.rawValue)) + } + if let _ = inputAdmins { + flags += Int32(1 << 1) + } + return network.request(Api.functions.channels.getAdminLog(flags: flags, channel: inputChannel, q: query ?? "", eventsFilter: eventsFilter, admins: inputAdmins, maxId: maxId, minId: minId, limit: limit)) |> mapToSignal { result in + + switch result { + case let .adminLogResults(apiEvents, apiChats, apiUsers): + var peers: [PeerId: Peer] = [:] + for apiChat in apiChats { + if let peer = parseTelegramGroupOrChannel(chat: apiChat) { + peers[peer.id] = peer + } + } + for apiUser in apiUsers { + let peer = TelegramUser(user: apiUser) + peers[peer.id] = peer + } + + var events: [AdminLogEvent] = [] + + for event in apiEvents { + switch event { + case let .channelAdminLogEvent(id, date, userId, apiAction): + var action: AdminLogEventAction? + switch apiAction { + case let .channelAdminLogEventActionChangeTitle(prev, new): + action = .changeTitle(prev: prev, new: new) + case let .channelAdminLogEventActionChangeAbout(prev, new): + action = .changeAbout(prev: prev, new: new) + case let .channelAdminLogEventActionChangeUsername(prev, new): + action = .changeUsername(prev: prev, new: new) + case let .channelAdminLogEventActionChangePhoto(prev, new): + action = .changePhoto(prev: telegramMediaImageFromApiPhoto(prev)?.representations ?? [], new: telegramMediaImageFromApiPhoto(new)?.representations ?? []) + case let .channelAdminLogEventActionToggleInvites(new): + action = .toggleInvites(boolFromApiValue(new)) + case let .channelAdminLogEventActionToggleSignatures(new): + action = .toggleSignatures(boolFromApiValue(new)) + case let .channelAdminLogEventActionUpdatePinned(new): + switch new { + case .messageEmpty: + action = .updatePinned(nil) + default: + if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) { + action = .updatePinned(rendered) + } + } + + case let .channelAdminLogEventActionEditMessage(prev, new): + if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) { + action = .editMessage(prev: prevRendered, new: newRendered) + } + case let .channelAdminLogEventActionDeleteMessage(message): + if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + action = .deleteMessage(rendered) + } + case .channelAdminLogEventActionParticipantJoin: + action = .participantJoin + case .channelAdminLogEventActionParticipantLeave: + action = .participantLeave + case let .channelAdminLogEventActionParticipantInvite(participant): + let participant = ChannelParticipant(apiParticipant: participant) + + if let peer = peers[participant.peerId] { + action = .participantInvite(RenderedChannelParticipant(participant: participant, peer: peer)) + } + case let .channelAdminLogEventActionParticipantToggleBan(prev, new): + let prevParticipant = ChannelParticipant(apiParticipant: prev) + let newParticipant = ChannelParticipant(apiParticipant: new) + + if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { + action = .participantToggleBan(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) + } + case let .channelAdminLogEventActionParticipantToggleAdmin(prev, new): + let prevParticipant = ChannelParticipant(apiParticipant: prev) + let newParticipant = ChannelParticipant(apiParticipant: new) + + if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { + action = .participantToggleAdmin(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) + } + case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset): + action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset)) + case let .channelAdminLogEventActionTogglePreHistoryHidden(value): + action = .togglePreHistoryHidden(value == .boolTrue) + case let .channelAdminLogEventActionDefaultBannedRights(prevBannedRights, newBannedRights): + action = .updateDefaultBannedRights(prev: TelegramChatBannedRights(apiBannedRights: prevBannedRights), new: TelegramChatBannedRights(apiBannedRights: newBannedRights)) + case let .channelAdminLogEventActionStopPoll(message): + if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + action = .pollStopped(rendered) + } + case let .channelAdminLogEventActionChangeLinkedChat(prevValue, newValue): + action = .linkedPeerUpdated(previous: prevValue == 0 ? nil : peers[PeerId(namespace: Namespaces.Peer.CloudChannel, id: prevValue)], updated: newValue == 0 ? nil : peers[PeerId(namespace: Namespaces.Peer.CloudChannel, id: newValue)]) + } + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + if let action = action { + events.append(AdminLogEvent(id: id, peerId: peerId, date: date, action: action)) + } + } + } + + return postbox.transaction { transaction -> AdminLogEventsResult in + updatePeers(transaction: transaction, peers: peers.map { $0.1 }, update: { return $1 }) + return AdminLogEventsResult(peerId: peerId, peers: peers, events: events) + } |> introduceError(MTRpcError.self) + } + + } |> mapError {_ in return .generic} + } + + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelAdmins.swift b/submodules/TelegramCore/TelegramCore/ChannelAdmins.swift new file mode 100644 index 0000000000..a3de627b7d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelAdmins.swift @@ -0,0 +1,90 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedChannelParticipant], NoError> { + return account.postbox.transaction { transaction -> Signal<[RenderedChannelParticipant], NoError> in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in + switch result { + case let .channelParticipants(count, participants, users): + var items: [RenderedChannelParticipant] = [] + + var peers: [PeerId: Peer] = [:] + var presences:[PeerId: PeerPresence] = [:] + for user in users { + let peer = TelegramUser(user: user) + peers[peer.id] = peer + if let presence = TelegramUserPresence(apiUser: user) { + presences[peer.id] = presence + } + } + + for participant in CachedChannelParticipants(apiParticipants: participants).participants { + if let peer = peers[participant.peerId] { + items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences)) + } + + } + + return account.postbox.transaction { transaction -> [RenderedChannelParticipant] in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData { + return cachedData.withUpdatedParticipantsSummary(cachedData.participantsSummary.withUpdatedAdminCount(count)) + } else { + return cachedData + } + }) + return items + } + case .channelParticipantsNotModified: + return .single([]) + } + } + } else { + return .single([]) + } + } |> switchToLatest +} + +public func channelAdminIds(postbox: Postbox, network: Network, peerId: PeerId, hash: Int32) -> Signal<[PeerId], NoError> { + return postbox.transaction { transaction in + if let peer = transaction.getPeer(peerId) as? TelegramChannel, case .group = peer.info, let apiChannel = apiInputChannel(peer) { + let api = Api.functions.channels.getParticipants(channel: apiChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: hash) + return network.request(api) |> retryRequest |> mapToSignal { result in + switch result { + case let .channelParticipants(_, participants, users): + let users = users.filter({ user in + return participants.contains(where: { participant in + switch participant { + case let .channelParticipantAdmin(_, userId, _, _, _, _): + return user.peerId.id == userId + case let .channelParticipantCreator(userId): + return user.peerId.id == userId + default: + return false + } + }) + }) + return .single(users.map({TelegramUser(user: $0).id})) + default: + return .complete() + } + } + } + return .complete() + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelBlacklist.swift b/submodules/TelegramCore/TelegramCore/ChannelBlacklist.swift new file mode 100644 index 0000000000..3ff892ebfe --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelBlacklist.swift @@ -0,0 +1,289 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private enum ChannelBlacklistFilter { + case restricted + case banned +} + +private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: ChannelBlacklistFilter) -> Signal<[RenderedChannelParticipant], NoError> { + return account.postbox.transaction { transaction -> Signal<[RenderedChannelParticipant], NoError> in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + let apiFilter: Api.ChannelParticipantsFilter + switch filter { + case .restricted: + apiFilter = .channelParticipantsBanned(q: "") + case .banned: + apiFilter = .channelParticipantsKicked(q: "") + } + return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: 0, limit: 100, hash: 0)) + |> retryRequest + |> map { result -> [RenderedChannelParticipant] in + var items: [RenderedChannelParticipant] = [] + switch result { + case let .channelParticipants(_, participants, users): + var peers: [PeerId: Peer] = [:] + var presences:[PeerId: PeerPresence] = [:] + for user in users { + let peer = TelegramUser(user: user) + peers[peer.id] = peer + if let presence = TelegramUserPresence(apiUser: user) { + presences[peer.id] = presence + } + } + + for participant in CachedChannelParticipants(apiParticipants: participants).participants { + if let peer = peers[participant.peerId] { + items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences)) + } + + } + case .channelParticipantsNotModified: + assertionFailure() + break + } + return items + } + } else { + return .single([]) + } + } |> switchToLatest +} + +public struct ChannelBlacklist { + public let banned: [RenderedChannelParticipant] + public let restricted: [RenderedChannelParticipant] + + public init(banned: [RenderedChannelParticipant], restricted: [RenderedChannelParticipant]) { + self.banned = banned + self.restricted = restricted + } + + public var isEmpty: Bool { + return banned.isEmpty && restricted.isEmpty + } + + public func withRemovedPeerId(_ memberId:PeerId) -> ChannelBlacklist { + var updatedRestricted = restricted + var updatedBanned = banned + + for i in 0 ..< updatedBanned.count { + if updatedBanned[i].peer.id == memberId { + updatedBanned.remove(at: i) + break + } + } + for i in 0 ..< updatedRestricted.count { + if updatedRestricted[i].peer.id == memberId { + updatedRestricted.remove(at: i) + break + } + } + return ChannelBlacklist(banned: updatedBanned, restricted: updatedRestricted) + } + + public func withRemovedParticipant(_ participant:RenderedChannelParticipant) -> ChannelBlacklist { + let updated = self.withRemovedPeerId(participant.participant.peerId) + var updatedRestricted = updated.restricted + var updatedBanned = updated.banned + + if case .member(_, _, _, let maybeBanInfo) = participant.participant, let banInfo = maybeBanInfo { + if banInfo.rights.flags.contains(.banReadMessages) { + updatedBanned.insert(participant, at: 0) + } else { + if !banInfo.rights.flags.isEmpty { + updatedRestricted.insert(participant, at: 0) + } + } + } + + + return ChannelBlacklist(banned: updatedBanned, restricted: updatedRestricted) + } +} + +public func channelBlacklistParticipants(account: Account, peerId: PeerId) -> Signal { + return combineLatest(fetchChannelBlacklist(account: account, peerId: peerId, filter: .restricted), fetchChannelBlacklist(account: account, peerId: peerId, filter: .banned)) + |> map { restricted, banned in + var r: [RenderedChannelParticipant] = [] + var b: [RenderedChannelParticipant] = [] + var peerIds = Set() + for participant in restricted { + if !peerIds.contains(participant.peer.id) { + peerIds.insert(participant.peer.id) + r.append(participant) + } + } + for participant in banned { + if !peerIds.contains(participant.peer.id) { + peerIds.insert(participant.peer.id) + b.append(participant) + } + } + return ChannelBlacklist(banned: b, restricted: r) + } +} + +public func updateChannelMemberBannedRights(account: Account, peerId: PeerId, memberId: PeerId, rights: TelegramChatBannedRights?) -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> { + return fetchChannelParticipant(account: account, peerId: peerId, participantId: memberId) + |> mapToSignal { currentParticipant -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in + return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer), let _ = transaction.getPeer(account.peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { + let updatedParticipant: ChannelParticipant + if let currentParticipant = currentParticipant, case let .member(_, invitedAt, _, currentBanInfo) = currentParticipant { + let banInfo: ChannelParticipantBannedInfo? + if let rights = rights, !rights.flags.isEmpty { + banInfo = ChannelParticipantBannedInfo(rights: rights, restrictedBy: currentBanInfo?.restrictedBy ?? account.peerId, timestamp: currentBanInfo?.timestamp ?? Int32(Date().timeIntervalSince1970), isMember: currentBanInfo?.isMember ?? true) + } else { + banInfo = nil + } + updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: invitedAt, adminInfo: nil, banInfo: banInfo) + } else { + let banInfo: ChannelParticipantBannedInfo? + if let rights = rights, !rights.flags.isEmpty { + banInfo = ChannelParticipantBannedInfo(rights: rights, restrictedBy: account.peerId, timestamp: Int32(Date().timeIntervalSince1970), isMember: false) + } else { + banInfo = nil + } + updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: nil, banInfo: banInfo) + } + + return account.network.request(Api.functions.channels.editBanned(channel: inputChannel, userId: inputUser, bannedRights: rights?.apiBannedRights ?? Api.ChatBannedRights.chatBannedRights(flags: 0, untilDate: 0))) + |> retryRequest + |> mapToSignal { result -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in + account.stateManager.addUpdates(result) + + var wasKicked = false + var wasBanned = false + var wasMember = false + var wasAdmin = false + if let currentParticipant = currentParticipant { + switch currentParticipant { + case .creator: + break + case let .member(_, _, adminInfo, banInfo): + if let _ = adminInfo { + wasAdmin = true + } + if let banInfo = banInfo, !banInfo.rights.flags.isEmpty { + if banInfo.rights.flags.contains(.banReadMessages) { + wasKicked = true + } else { + wasBanned = true + wasMember = true + } + } else { + wasMember = true + } + } + } + + var isKicked = false + var isBanned = false + if let rights = rights, !rights.flags.isEmpty { + if rights.flags.contains(.banReadMessages) { + isKicked = true + } else { + isBanned = true + } + } + + let isMember = !wasKicked && !isKicked + + return account.postbox.transaction { transaction -> (ChannelParticipant?, RenderedChannelParticipant?, Bool) in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData { + var updatedData = cachedData + if isKicked != wasKicked { + if let kickedCount = updatedData.participantsSummary.kickedCount { + updatedData = updatedData.withUpdatedParticipantsSummary(updatedData.participantsSummary.withUpdatedKickedCount(max(0, kickedCount + (isKicked ? 1 : -1)))) + } + } + + if isBanned != wasBanned { + if let bannedCount = updatedData.participantsSummary.bannedCount { + updatedData = updatedData.withUpdatedParticipantsSummary(updatedData.participantsSummary.withUpdatedBannedCount(max(0, bannedCount + (isBanned ? 1 : -1)))) + } + } + + if wasAdmin { + if let adminCount = updatedData.participantsSummary.adminCount { + updatedData = updatedData.withUpdatedParticipantsSummary(updatedData.participantsSummary.withUpdatedAdminCount(max(0, adminCount - 1))) + } + } + + if isMember != wasMember { + if let memberCount = updatedData.participantsSummary.memberCount { + updatedData = updatedData.withUpdatedParticipantsSummary(updatedData.participantsSummary.withUpdatedMemberCount(max(0, memberCount + (isMember ? 1 : -1)))) + } + } + + return updatedData + } else { + return cachedData + } + }) + var peers: [PeerId: Peer] = [:] + var presences: [PeerId: PeerPresence] = [:] + peers[memberPeer.id] = memberPeer + if let presence = transaction.getPeerPresence(peerId: memberPeer.id) { + presences[memberPeer.id] = presence + } + if case let .member(_, _, _, maybeBanInfo) = updatedParticipant, let banInfo = maybeBanInfo { + if let peer = transaction.getPeer(banInfo.restrictedBy) { + peers[peer.id] = peer + } + } + + return (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: memberPeer, peers: peers, presences: presences), isMember) + } + } + } else { + return .complete() + } + } + |> switchToLatest + } +} + +public func updateDefaultChannelMemberBannedRights(account: Account, peerId: PeerId, rights: TelegramChatBannedRights) -> Signal { + return account.postbox.transaction { transaction -> Signal in + guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let _ = transaction.getPeer(account.peerId) else { + return .complete() + } + return account.network.request(Api.functions.messages.editChatDefaultBannedRights(peer: inputPeer, bannedRights: rights.apiBannedRights)) + |> retryRequest + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return account.postbox.transaction { transaction -> Void in + guard let peer = transaction.getPeer(peerId) else { + return + } + if let peer = peer as? TelegramGroup { + updatePeers(transaction: transaction, peers: [peer.updateDefaultBannedRights(rights, version: peer.version)], update: { _, updated in + return updated + }) + } else if let peer = peer as? TelegramChannel { + updatePeers(transaction: transaction, peers: [peer.withUpdatedDefaultBannedRights(rights)], update: { _, updated in + return updated + }) + } + } + |> ignoreValues + } + } + |> switchToLatest +} + diff --git a/submodules/TelegramCore/TelegramCore/ChannelCreation.swift b/submodules/TelegramCore/TelegramCore/ChannelCreation.swift new file mode 100644 index 0000000000..84aaedbb76 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelCreation.swift @@ -0,0 +1,87 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private func createChannel(account: Account, title: String, description: String?, isSupergroup:Bool) -> Signal { + return account.postbox.transaction { transaction -> Signal in + return account.network.request(Api.functions.channels.createChannel(flags: isSupergroup ? 1 << 1 : 1 << 0, title: title, about: description ?? ""), automaticFloodWait: false) + |> mapError { error -> CreateChannelError in + if error.errorDescription == "USER_RESTRICTED" { + return .restricted + } else { + return .generic + } + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + if let message = updates.messages.first, let peerId = apiMessagePeerId(message) { + return account.postbox.multiplePeersView([peerId]) + |> filter { view in + return view.peers[peerId] != nil + } + |> take(1) + |> map { _ in + return peerId + } + |> introduceError(CreateChannelError.self) + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) + } else { + return .fail(.generic) + } + } + } + |> introduceError(CreateChannelError.self) + |> switchToLatest +} + +public enum CreateChannelError { + case generic + case restricted +} + +public func createChannel(account: Account, title: String, description: String?) -> Signal { + return createChannel(account: account, title: title, description: description, isSupergroup: false) +} + +public func createSupergroup(account: Account, title: String, description: String?) -> Signal { + return createChannel(account: account, title: title, description: description, isSupergroup: true) +} + +public enum DeleteChannelError { + case generic +} + +public func deleteChannel(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Api.InputChannel? in + return transaction.getPeer(peerId).flatMap(apiInputChannel) + } + |> mapError { _ -> DeleteChannelError in return .generic } + |> mapToSignal { inputChannel -> Signal in + if let inputChannel = inputChannel { + return account.network.request(Api.functions.channels.deleteChannel(channel: inputChannel)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .fail(.generic) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + } + return .complete() + } + } else { + return .fail(.generic) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelHistoryAvailabilitySettings.swift b/submodules/TelegramCore/TelegramCore/ChannelHistoryAvailabilitySettings.swift new file mode 100644 index 0000000000..24f77297ba --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelHistoryAvailabilitySettings.swift @@ -0,0 +1,52 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum ChannelHistoryAvailabilityError { + case generic + case hasNotPermissions +} + +public func updateChannelHistoryAvailabilitySettingsInteractively(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, historyAvailableForNewMembers: Bool) -> Signal { + return postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> introduceError(ChannelHistoryAvailabilityError.self) + |> mapToSignal { peer in + + guard let peer = peer, let inputChannel = apiInputChannel(peer) else { + return .fail(.generic) + } + + return network.request(Api.functions.channels.togglePreHistoryHidden(channel: inputChannel, enabled: historyAvailableForNewMembers ? .boolFalse : .boolTrue)) + |> `catch` { error -> Signal in + if error.errorDescription == "CHAT_ADMIN_REQUIRED" { + return .fail(.hasNotPermissions) + } + return .fail(.generic) + } + |> mapToSignal { updates -> Signal in + accountStateManager.addUpdates(updates) + return postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in + if let currentData = currentData as? CachedChannelData { + var flags = currentData.flags + if historyAvailableForNewMembers { + flags.insert(.preHistoryEnabled) + } else { + flags.remove(.preHistoryEnabled) + } + return currentData.withUpdatedFlags(flags) + } else { + return currentData + } + }) + } |> introduceError(ChannelHistoryAvailabilityError.self) + } + + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelMembers.swift b/submodules/TelegramCore/TelegramCore/ChannelMembers.swift new file mode 100644 index 0000000000..3dc0783a3d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelMembers.swift @@ -0,0 +1,105 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ChannelMembersCategoryFilter { + case all + case search(String) +} + +public enum ChannelMembersCategory { + case recent(ChannelMembersCategoryFilter) + case admins + case contacts(ChannelMembersCategoryFilter) + case bots(ChannelMembersCategoryFilter) + case restricted(ChannelMembersCategoryFilter) + case banned(ChannelMembersCategoryFilter) +} + +public func channelMembers(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, category: ChannelMembersCategory = .recent(.all), offset: Int32 = 0, limit: Int32 = 64, hash: Int32 = 0) -> Signal<[RenderedChannelParticipant]?, NoError> { + return postbox.transaction { transaction -> Signal<[RenderedChannelParticipant]?, NoError> in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + let apiFilter: Api.ChannelParticipantsFilter + switch category { + case let .recent(filter): + switch filter { + case .all: + apiFilter = .channelParticipantsRecent + case let .search(query): + apiFilter = .channelParticipantsSearch(q: query) + } + case .admins: + apiFilter = .channelParticipantsAdmins + case let .contacts(filter): + switch filter { + case .all: + apiFilter = .channelParticipantsContacts(q: "") + case let .search(query): + apiFilter = .channelParticipantsContacts(q: query) + } + case .bots: + apiFilter = .channelParticipantsBots + case let .restricted(filter): + switch filter { + case .all: + apiFilter = .channelParticipantsBanned(q: "") + case let .search(query): + apiFilter = .channelParticipantsBanned(q: query) + } + case let .banned(filter): + switch filter { + case .all: + apiFilter = .channelParticipantsKicked(q: "") + case let .search(query): + apiFilter = .channelParticipantsKicked(q: query) + } + } + return network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: offset, limit: limit, hash: hash)) + |> retryRequest + |> mapToSignal { result -> Signal<[RenderedChannelParticipant]?, NoError> in + return postbox.transaction { transaction -> [RenderedChannelParticipant]? in + var items: [RenderedChannelParticipant] = [] + switch result { + case let .channelParticipants(_, participants, users): + var peers: [PeerId: Peer] = [:] + var presences: [PeerId: PeerPresence] = [:] + for user in users { + let peer = TelegramUser(user: user) + peers[peer.id] = peer + if let presence = TelegramUserPresence(apiUser: user) { + presences[peer.id] = presence + } + } + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences) + + for participant in CachedChannelParticipants(apiParticipants: participants).participants { + if let peer = peers[participant.peerId] { + items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences)) + } + + } + case .channelParticipantsNotModified: + return nil + } + return items + } + } + } else { + return .single([]) + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelMessageStateVersionAttribute.swift b/submodules/TelegramCore/TelegramCore/ChannelMessageStateVersionAttribute.swift new file mode 100644 index 0000000000..4e352ed0a6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelMessageStateVersionAttribute.swift @@ -0,0 +1,22 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ChannelMessageStateVersionAttribute: MessageAttribute { + public let pts: Int32 + + public init(pts: Int32) { + self.pts = pts + } + + required public init(decoder: PostboxDecoder) { + self.pts = decoder.decodeInt32ForKey("p", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.pts, forKey: "p") + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelOwnershipTransfer.swift b/submodules/TelegramCore/TelegramCore/ChannelOwnershipTransfer.swift new file mode 100644 index 0000000000..079826663b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelOwnershipTransfer.swift @@ -0,0 +1,96 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public enum ChannelOwnershipTransferError { + case generic + case twoStepAuthMissing + case twoStepAuthTooFresh(Int32) + case authSessionTooFresh(Int32) + case requestPassword + case invalidPassword + case adminsTooMuch + case userPublicChannelsTooMuch + case restricted + case userBlocked +} + +public func updateChannelOwnership(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, channelId: PeerId, memberId: PeerId, password: String?) -> Signal { + return postbox.transaction { transaction -> (channel: Peer?, user: Peer?) in + return (channel: transaction.getPeer(channelId), user: transaction.getPeer(memberId)) + } + |> introduceError(ChannelOwnershipTransferError.self) + |> mapToSignal { channel, user -> Signal in + guard let channel = channel, let user = user else { + return .fail(.generic) + } + guard let apiChannel = apiInputChannel(channel) else { + return .fail(.generic) + } + guard let apiUser = apiInputUser(user) else { + return .fail(.generic) + } + + let checkPassword: Signal + if let password = password, !password.isEmpty { + checkPassword = twoStepAuthData(network) + |> mapError { _ in ChannelOwnershipTransferError.generic } + |> mapToSignal { authData -> Signal in + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))) + } else { + return .fail(.twoStepAuthMissing) + } + } + } else { + checkPassword = .single(.inputCheckPasswordEmpty) + } + + return checkPassword + |> mapToSignal { password -> Signal in + return network.request(Api.functions.channels.editCreator(channel: apiChannel, userId: apiUser, password: password)) + |> mapError { error -> ChannelOwnershipTransferError in + if error.errorDescription == "PASSWORD_HASH_INVALID" { + if case .inputCheckPasswordEmpty = password { + return .requestPassword + } else { + return .invalidPassword + } + } else if error.errorDescription == "PASSWORD_MISSING" { + return .twoStepAuthMissing + } else if error.errorDescription.hasPrefix("PASSWORD_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "PASSWORD_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .twoStepAuthTooFresh(value) + } + } else if error.errorDescription.hasPrefix("SESSION_TOO_FRESH_") { + let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "SESSION_TOO_FRESH_".count)...]) + if let value = Int32(timeout) { + return .authSessionTooFresh(value) + } + } else if error.errorDescription == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH" { + return .userPublicChannelsTooMuch + } else if error.errorDescription == "ADMINS_TOO_MUCH" { + return .adminsTooMuch + } else if error.errorDescription == "USER_PRIVACY_RESTRICTED" { + return .restricted + } else if error.errorDescription == "USER_BLOCKED" { + return .userBlocked + } + return .generic + } + |> mapToSignal { updates -> Signal in + accountStateManager.addUpdates(updates) + return.complete() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelParticipants.swift b/submodules/TelegramCore/TelegramCore/ChannelParticipants.swift new file mode 100644 index 0000000000..76e4c9bae6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelParticipants.swift @@ -0,0 +1,91 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct RenderedChannelParticipant: Equatable { + public let participant: ChannelParticipant + public let peer: Peer + public let peers: [PeerId: Peer] + public let presences: [PeerId: PeerPresence] + + public init(participant: ChannelParticipant, peer: Peer, peers: [PeerId: Peer] = [:], presences: [PeerId: PeerPresence] = [:]) { + self.participant = participant + self.peer = peer + self.peers = peers + self.presences = presences + } + + public static func ==(lhs: RenderedChannelParticipant, rhs: RenderedChannelParticipant) -> Bool { + return lhs.participant == rhs.participant && lhs.peer.isEqual(rhs.peer) + } +} + +func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + let admins = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 0, hash: 0)) + let members = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 0, hash: 0)) + let banned = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsBanned(q: ""), offset: 0, limit: 0, hash: 0)) + let kicked = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsKicked(q: ""), offset: 0, limit: 0, hash: 0)) + return combineLatest(admins, members, banned, kicked) + |> mapToSignal { admins, members, banned, kicked -> Signal in + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedChannelData { + let adminCount: Int32 + switch admins { + case let .channelParticipants(count, _, _): + adminCount = count + case .channelParticipantsNotModified: + assertionFailure() + adminCount = 0 + } + let memberCount: Int32 + switch members { + case let .channelParticipants(count, _, _): + memberCount = count + case .channelParticipantsNotModified: + assertionFailure() + memberCount = 0 + } + let bannedCount: Int32 + switch banned { + case let .channelParticipants(count, _, _): + bannedCount = count + case .channelParticipantsNotModified: + assertionFailure() + bannedCount = 0 + } + let kickedCount: Int32 + switch kicked { + case let .channelParticipants(count, _, _): + kickedCount = count + case .channelParticipantsNotModified: + assertionFailure() + kickedCount = 0 + } + return current.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: memberCount, adminCount: adminCount, bannedCount: bannedCount, kickedCount: kickedCount)) + } + return current + }) + } |> mapError { _ -> MTRpcError in return MTRpcError(errorCode: 0, errorDescription: "") } + } + |> `catch` { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelState.swift b/submodules/TelegramCore/TelegramCore/ChannelState.swift new file mode 100644 index 0000000000..56694abad0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelState.swift @@ -0,0 +1,88 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +final class ChannelState: PeerChatState, Equatable, CustomStringConvertible { + let pts: Int32 + let invalidatedPts: Int32? + + init(pts: Int32, invalidatedPts: Int32?) { + self.pts = pts + self.invalidatedPts = invalidatedPts + } + + init(decoder: PostboxDecoder) { + self.pts = decoder.decodeInt32ForKey("pts", orElse: 0) + self.invalidatedPts = decoder.decodeOptionalInt32ForKey("ipts") + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.pts, forKey: "pts") + if let invalidatedPts = self.invalidatedPts { + encoder.encodeInt32(invalidatedPts, forKey: "ipts") + } else { + encoder.encodeNil(forKey: "ipts") + } + } + + func withUpdatedPts(_ pts: Int32) -> ChannelState { + return ChannelState(pts: pts, invalidatedPts: self.invalidatedPts) + } + + func withUpdatedInvalidatedPts(_ invalidatedPts: Int32?) -> ChannelState { + return ChannelState(pts: self.pts, invalidatedPts: invalidatedPts) + } + + func equals(_ other: PeerChatState) -> Bool { + if let other = other as? ChannelState, other == self { + return true + } + return false + } + + var description: String { + return "(pts: \(self.pts))" + } +} + +func ==(lhs: ChannelState, rhs: ChannelState) -> Bool { + return lhs.pts == rhs.pts && lhs.invalidatedPts == rhs.invalidatedPts +} + +struct ChannelUpdate { + let update: Api.Update + let ptsRange: (Int32, Int32)? +} + +func channelUpdatesByPeerId(updates: [ChannelUpdate]) -> [PeerId: [ChannelUpdate]] { + var grouped: [PeerId: [ChannelUpdate]] = [:] + + for update in updates { + var peerId: PeerId? + switch update.update { + case let .updateNewChannelMessage(message, _, _): + peerId = apiMessagePeerId(message) + case let .updateDeleteChannelMessages(channelId, _, _, _): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + case let .updateEditChannelMessage(message, _, _): + peerId = apiMessagePeerId(message) + case let .updateChannelWebPage(channelId, _, _, _): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + default: + break + } + + if let peerId = peerId { + if grouped[peerId] == nil { + grouped[peerId] = [update] + } else { + grouped[peerId]!.append(update) + } + } + } + + return grouped +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelStats.swift b/submodules/TelegramCore/TelegramCore/ChannelStats.swift new file mode 100644 index 0000000000..4e1b8a9f63 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChannelStats.swift @@ -0,0 +1,38 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public enum ChannelStatsUrlError { + case generic +} + +public func channelStatsUrl(postbox: Postbox, network: Network, peerId: PeerId, params: String, darkTheme: Bool) -> Signal { + return postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> introduceError(ChannelStatsUrlError.self) + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .fail(.generic) + } + var flags: Int32 = 0 + if darkTheme { + flags |= (1 << 0) + } + return network.request(Api.functions.messages.getStatsURL(flags: flags, peer: inputPeer, params: params)) + |> map { result -> String in + switch result { + case let .statsURL(url): + return url + } + } + |> `catch` { _ -> Signal in + return .fail(.generic) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChatContextResult.swift b/submodules/TelegramCore/TelegramCore/ChatContextResult.swift new file mode 100644 index 0000000000..8a507cf753 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChatContextResult.swift @@ -0,0 +1,462 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ChatContextResultMessage: PostboxCoding, Equatable { + case auto(caption: String, entities: TextEntitiesMessageAttribute?, replyMarkup: ReplyMarkupMessageAttribute?) + case text(text: String, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, replyMarkup: ReplyMarkupMessageAttribute?) + case mapLocation(media: TelegramMediaMap, replyMarkup: ReplyMarkupMessageAttribute?) + case contact(media: TelegramMediaContact, replyMarkup: ReplyMarkupMessageAttribute?) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_v", orElse: 0) { + case 0: + self = .auto(caption: decoder.decodeStringForKey("c", orElse: ""), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + case 1: + self = .text(text: decoder.decodeStringForKey("t", orElse: ""), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, disableUrlPreview: decoder.decodeInt32ForKey("du", orElse: 0) != 0, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + case 2: + self = .mapLocation(media: decoder.decodeObjectForKey("l") as! TelegramMediaMap, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + case 3: + self = .contact(media: decoder.decodeObjectForKey("c") as! TelegramMediaContact, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute) + default: + self = .auto(caption: "", entities: nil, replyMarkup: nil) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .auto(caption, entities, replyMarkup): + encoder.encodeInt32(0, forKey: "_v") + encoder.encodeString(caption, forKey: "c") + if let entities = entities { + encoder.encodeObject(entities, forKey: "e") + } else { + encoder.encodeNil(forKey: "e") + } + if let replyMarkup = replyMarkup { + encoder.encodeObject(replyMarkup, forKey: "m") + } else { + encoder.encodeNil(forKey: "m") + } + case let .text(text, entities, disableUrlPreview, replyMarkup): + encoder.encodeInt32(1, forKey: "_v") + encoder.encodeString(text, forKey: "t") + if let entities = entities { + encoder.encodeObject(entities, forKey: "e") + } else { + encoder.encodeNil(forKey: "e") + } + encoder.encodeInt32(disableUrlPreview ? 1 : 0, forKey: "du") + if let replyMarkup = replyMarkup { + encoder.encodeObject(replyMarkup, forKey: "m") + } else { + encoder.encodeNil(forKey: "m") + } + case let .mapLocation(media, replyMarkup): + encoder.encodeInt32(2, forKey: "_v") + encoder.encodeObject(media, forKey: "l") + if let replyMarkup = replyMarkup { + encoder.encodeObject(replyMarkup, forKey: "m") + } else { + encoder.encodeNil(forKey: "m") + } + case let .contact(media, replyMarkup): + encoder.encodeInt32(3, forKey: "_v") + encoder.encodeObject(media, forKey: "c") + if let replyMarkup = replyMarkup { + encoder.encodeObject(replyMarkup, forKey: "m") + } else { + encoder.encodeNil(forKey: "m") + } + } + } + + public static func ==(lhs: ChatContextResultMessage, rhs: ChatContextResultMessage) -> Bool { + switch lhs { + case let .auto(lhsCaption, lhsEntities, lhsReplyMarkup): + if case let .auto(rhsCaption, rhsEntities, rhsReplyMarkup) = rhs { + if lhsCaption != rhsCaption { + return false + } + if lhsEntities != rhsEntities { + return false + } + if lhsReplyMarkup != rhsReplyMarkup { + return false + } + return true + } else { + return false + } + case let .text(lhsText, lhsEntities, lhsDisableUrlPreview, lhsReplyMarkup): + if case let .text(rhsText, rhsEntities, rhsDisableUrlPreview, rhsReplyMarkup) = rhs { + if lhsText != rhsText { + return false + } + if lhsEntities != rhsEntities { + return false + } + if lhsDisableUrlPreview != rhsDisableUrlPreview { + return false + } + if lhsReplyMarkup != rhsReplyMarkup { + return false + } + return true + } else { + return false + } + case let .mapLocation(lhsMedia, lhsReplyMarkup): + if case let .mapLocation(rhsMedia, rhsReplyMarkup) = rhs { + if !lhsMedia.isEqual(to: rhsMedia) { + return false + } + if lhsReplyMarkup != rhsReplyMarkup { + return false + } + return true + } else { + return false + } + case let .contact(lhsMedia, lhsReplyMarkup): + if case let .contact(rhsMedia, rhsReplyMarkup) = rhs { + if !lhsMedia.isEqual(to: rhsMedia) { + return false + } + if lhsReplyMarkup != rhsReplyMarkup { + return false + } + return true + } else { + return false + } + } + } +} + +public enum ChatContextResult: Equatable { + case externalReference(queryId: Int64, id: String, type: String, title: String?, description: String?, url: String?, content: TelegramMediaWebFile?, thumbnail: TelegramMediaWebFile?, message: ChatContextResultMessage) + case internalReference(queryId: Int64, id: String, type: String, title: String?, description: String?, image: TelegramMediaImage?, file: TelegramMediaFile?, message: ChatContextResultMessage) + + public var queryId: Int64 { + switch self { + case let .externalReference(queryId, _, _, _, _, _, _, _, _): + return queryId + case let .internalReference(queryId, _, _, _, _, _, _, _): + return queryId + } + } + + public var id: String { + switch self { + case let .externalReference(_, id, _, _, _, _, _, _, _): + return id + case let .internalReference(_, id, _, _, _, _, _, _): + return id + } + } + + public var type: String { + switch self { + case let .externalReference(_, _, type, _, _, _, _, _, _): + return type + case let .internalReference(_, _, type, _, _, _, _, _): + return type + } + } + + public var title: String? { + switch self { + case let .externalReference(_, _, _, title, _, _, _, _, _): + return title + case let .internalReference(_, _, _, title, _, _, _, _): + return title + } + } + + public var description: String? { + switch self { + case let .externalReference(_, _, _, _, description, _, _, _, _): + return description + case let .internalReference(_, _, _, _, description, _, _, _): + return description + } + } + + public var message: ChatContextResultMessage { + switch self { + case let .externalReference(_, _, _, _, _, _, _, _, message): + return message + case let .internalReference(_, _, _, _, _, _, _, message): + return message + } + } + + public static func ==(lhs: ChatContextResult, rhs: ChatContextResult) -> Bool { + switch lhs { + //id: String, type: String, title: String?, description: String?, url: String?, content: TelegramMediaWebFile?, thumbnail: TelegramMediaWebFile?, message: ChatContextResultMessage + case let .externalReference(lhsQueryId, lhsId, lhsType, lhsTitle, lhsDescription, lhsUrl, lhsContent, lhsThumbnail, lhsMessage): + if case let .externalReference(rhsQueryId, rhsId, rhsType, rhsTitle, rhsDescription, rhsUrl, rhsContent, rhsThumbnail, rhsMessage) = rhs { + if lhsQueryId != rhsQueryId { + return false + } + if lhsId != rhsId { + return false + } + if lhsType != rhsType { + return false + } + if lhsTitle != rhsTitle { + return false + } + if lhsDescription != rhsDescription { + return false + } + if lhsUrl != rhsUrl { + return false + } + if let lhsContent = lhsContent, let rhsContent = rhsContent { + if !lhsContent.isEqual(to: rhsContent) { + return false + } + } else if (lhsContent != nil) != (rhsContent != nil) { + return false + } + if let lhsThumbnail = lhsThumbnail, let rhsThumbnail = rhsThumbnail { + if !lhsThumbnail.isEqual(to: rhsThumbnail) { + return false + } + } else if (lhsThumbnail != nil) != (rhsThumbnail != nil) { + return false + } + if lhsMessage != rhsMessage { + return false + } + return true + } else { + return false + } + case let .internalReference(lhsQueryId, lhsId, lhsType, lhsTitle, lhsDescription, lhsImage, lhsFile, lhsMessage): + if case let .internalReference(rhsQueryId, rhsId, rhsType, rhsTitle, rhsDescription, rhsImage, rhsFile, rhsMessage) = rhs { + if lhsQueryId != rhsQueryId { + return false + } + if lhsId != rhsId { + return false + } + if lhsType != rhsType { + return false + } + if lhsTitle != rhsTitle { + return false + } + if lhsDescription != rhsDescription { + return false + } + if let lhsImage = lhsImage, let rhsImage = rhsImage { + if !lhsImage.isEqual(to: rhsImage) { + return false + } + } else if (lhsImage != nil) != (rhsImage != nil) { + return false + } + if let lhsFile = lhsFile, let rhsFile = rhsFile { + if !lhsFile.isEqual(to: rhsFile) { + return false + } + } else if (lhsFile != nil) != (rhsFile != nil) { + return false + } + if lhsMessage != rhsMessage { + return false + } + return true + } else { + return false + } + } + } +} + +public enum ChatContextResultCollectionPresentation { + case media + case list +} + +public struct ChatContextResultSwitchPeer: Equatable { + public let text: String + public let startParam: String + + public static func ==(lhs: ChatContextResultSwitchPeer, rhs: ChatContextResultSwitchPeer) -> Bool { + return lhs.text == rhs.text && lhs.startParam == rhs.startParam + } +} + +public final class ChatContextResultCollection: Equatable { + public let botId: PeerId + public let peerId: PeerId + public let query: String + public let geoPoint: (Double, Double)? + public let queryId: Int64 + public let nextOffset: String? + public let presentation: ChatContextResultCollectionPresentation + public let switchPeer: ChatContextResultSwitchPeer? + public let results: [ChatContextResult] + public let cacheTimeout: Int32 + + public init(botId: PeerId, peerId: PeerId, query: String, geoPoint: (Double, Double)?, queryId: Int64, nextOffset: String?, presentation: ChatContextResultCollectionPresentation, switchPeer: ChatContextResultSwitchPeer?, results: [ChatContextResult], cacheTimeout: Int32) { + self.botId = botId + self.peerId = peerId + self.query = query + self.geoPoint = geoPoint + self.queryId = queryId + self.nextOffset = nextOffset + self.presentation = presentation + self.switchPeer = switchPeer + self.results = results + self.cacheTimeout = cacheTimeout + } + + public static func ==(lhs: ChatContextResultCollection, rhs: ChatContextResultCollection) -> Bool { + if lhs.botId != rhs.botId { + return false + } + if lhs.peerId != rhs.peerId { + return false + } + if lhs.queryId != rhs.queryId { + return false + } + if lhs.query != rhs.query { + return false + } + if lhs.geoPoint?.0 != rhs.geoPoint?.0 || lhs.geoPoint?.1 != rhs.geoPoint?.1 { + return false + } + if lhs.nextOffset != rhs.nextOffset { + return false + } + if lhs.presentation != rhs.presentation { + return false + } + if lhs.switchPeer != rhs.switchPeer { + return false + } + if lhs.results != rhs.results { + return false + } + if lhs.cacheTimeout != rhs.cacheTimeout { + return false + } + return true + } +} + +extension ChatContextResultMessage { + init(apiMessage: Api.BotInlineMessage) { + switch apiMessage { + case let .botInlineMessageMediaAuto(_, message, entities, replyMarkup): + var parsedEntities: TextEntitiesMessageAttribute? + if let entities = entities, !entities.isEmpty { + parsedEntities = TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)) + } + var parsedReplyMarkup: ReplyMarkupMessageAttribute? + if let replyMarkup = replyMarkup { + parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + } + self = .auto(caption: message, entities: parsedEntities, replyMarkup: parsedReplyMarkup) + case let .botInlineMessageText(flags, message, entities, replyMarkup): + var parsedEntities: TextEntitiesMessageAttribute? + if let entities = entities, !entities.isEmpty { + parsedEntities = TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)) + } + var parsedReplyMarkup: ReplyMarkupMessageAttribute? + if let replyMarkup = replyMarkup { + parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + } + self = .text(text: message, entities: parsedEntities, disableUrlPreview: (flags & (1 << 0)) != 0, replyMarkup: parsedReplyMarkup) + case let .botInlineMessageMediaGeo(_, geo, replyMarkup): + let media = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil) + var parsedReplyMarkup: ReplyMarkupMessageAttribute? + if let replyMarkup = replyMarkup { + parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + } + self = .mapLocation(media: media, replyMarkup: parsedReplyMarkup) + case let .botInlineMessageMediaVenue(_, geo, title, address, provider, venueId, venueType, replyMarkup): + let media = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId, venueType: venueType, liveBroadcastingTimeout: nil) + var parsedReplyMarkup: ReplyMarkupMessageAttribute? + if let replyMarkup = replyMarkup { + parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + } + self = .mapLocation(media: media, replyMarkup: parsedReplyMarkup) + case let .botInlineMessageMediaContact(_, phoneNumber, firstName, lastName, vcard, replyMarkup): + let media = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: nil, vCardData: vcard.isEmpty ? nil : vcard) + var parsedReplyMarkup: ReplyMarkupMessageAttribute? + if let replyMarkup = replyMarkup { + parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + } + self = .contact(media: media, replyMarkup: parsedReplyMarkup) + } + } +} + +extension ChatContextResult { + init(apiResult: Api.BotInlineResult, queryId: Int64) { + switch apiResult { + case let .botInlineResult(_, id, type, title, description, url, thumb, content, sendMessage): + self = .externalReference(queryId: queryId, id: id, type: type, title: title, description: description, url: url, content: content.flatMap(TelegramMediaWebFile.init), thumbnail: thumb.flatMap(TelegramMediaWebFile.init), message: ChatContextResultMessage(apiMessage: sendMessage)) + case let .botInlineMediaResult(_, id, type, photo, document, title, description, sendMessage): + var image: TelegramMediaImage? + var file: TelegramMediaFile? + if let photo = photo, let parsedImage = telegramMediaImageFromApiPhoto(photo) { + image = parsedImage + } + if let document = document, let parsedFile = telegramMediaFileFromApiDocument(document) { + file = parsedFile + } + self = .internalReference(queryId: queryId, id: id, type: type, title: title, description: description, image: image, file: file, message: ChatContextResultMessage(apiMessage: sendMessage)) + } + } +} + +extension ChatContextResultSwitchPeer { + init(apiSwitchPeer: Api.InlineBotSwitchPM) { + switch apiSwitchPeer { + case let .inlineBotSwitchPM(text, startParam): + self.init(text: text, startParam: startParam) + } + } +} + +extension ChatContextResultCollection { + convenience init(apiResults: Api.messages.BotResults, botId: PeerId, peerId: PeerId, query: String, geoPoint: (Double, Double)?) { + switch apiResults { + case let .botResults(flags, queryId, nextOffset, switchPm, results, cacheTime, _): + var switchPeer: ChatContextResultSwitchPeer? + if let switchPm = switchPm { + switchPeer = ChatContextResultSwitchPeer(apiSwitchPeer: switchPm) + } + let parsedResults = results.map({ ChatContextResult(apiResult: $0, queryId: queryId) }) + /*.filter({ result in + switch result { + case .internalReference: + return false + default: + return true + } + })*/ + self.init(botId: botId, peerId: peerId, query: query, geoPoint: geoPoint, queryId: queryId, nextOffset: nextOffset, presentation: (flags & (1 << 0) != 0) ? .media : .list, switchPeer: switchPeer, results: parsedResults, cacheTimeout: cacheTime) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift b/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift new file mode 100644 index 0000000000..9d9f27f5f6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift @@ -0,0 +1,486 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct HistoryPreloadIndex: Comparable { + public let index: ChatListIndex? + public let hasUnread: Bool + public let isMuted: Bool + public let isPriority: Bool + + public static func <(lhs: HistoryPreloadIndex, rhs: HistoryPreloadIndex) -> Bool { + if lhs.isPriority != rhs.isPriority { + if lhs.isPriority { + return true + } else { + return false + } + } + if lhs.isMuted != rhs.isMuted { + if lhs.isMuted { + return false + } else { + return true + } + } + if lhs.hasUnread != rhs.hasUnread { + if lhs.hasUnread { + return true + } else { + return false + } + } + if let lhsIndex = lhs.index, let rhsIndex = rhs.index { + return lhsIndex > rhsIndex + } else if lhs.index != nil { + return true + } else if rhs.index != nil { + return false + } else { + return true + } + } +} + +private struct HistoryPreloadHole: Hashable, Comparable { + let preloadIndex: HistoryPreloadIndex + let hole: MessageOfInterestHole + + static func ==(lhs: HistoryPreloadHole, rhs: HistoryPreloadHole) -> Bool { + return lhs.preloadIndex == rhs.preloadIndex && lhs.hole == rhs.hole + } + + static func <(lhs: HistoryPreloadHole, rhs: HistoryPreloadHole) -> Bool { + return lhs.preloadIndex < rhs.preloadIndex + } + + var hashValue: Int { + return self.preloadIndex.index.hashValue &* 31 &+ self.hole.hashValue + } +} + +private final class HistoryPreloadEntry: Comparable { + var hole: HistoryPreloadHole + private var isStarted = false + private let disposable = MetaDisposable() + + init(hole: HistoryPreloadHole) { + self.hole = hole + } + + static func ==(lhs: HistoryPreloadEntry, rhs: HistoryPreloadEntry) -> Bool { + return lhs.hole == rhs.hole + } + + static func <(lhs: HistoryPreloadEntry, rhs: HistoryPreloadEntry) -> Bool { + return lhs.hole < rhs.hole + } + + func startIfNeeded(postbox: Postbox, accountPeerId: PeerId, download: Signal, queue: Queue) { + if !self.isStarted { + self.isStarted = true + + let hole = self.hole.hole + let signal: Signal = .complete() + |> delay(0.3, queue: queue) + |> then( + download + |> take(1) + |> deliverOn(queue) + |> mapToSignal { download -> Signal in + switch hole.hole { + case let .peer(peerHole): + return fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .download(download), postbox: postbox, peerId: peerHole.peerId, namespace: peerHole.namespace, direction: hole.direction, space: .everywhere, limit: 60) + } + } + ) + self.disposable.set(signal.start()) + } + } + + deinit { + self.disposable.dispose() + } +} + +private final class HistoryPreloadViewContext { + var index: ChatListIndex? + var hasUnread: Bool? + var isMuted: Bool? + var isPriority: Bool + let disposable = MetaDisposable() + var hole: MessageOfInterestHole? + var media: [HolesViewMedia] = [] + + var preloadIndex: HistoryPreloadIndex { + return HistoryPreloadIndex(index: self.index, hasUnread: self.hasUnread ?? false, isMuted: self.isMuted ?? true, isPriority: self.isPriority) + } + + var currentHole: HistoryPreloadHole? { + if let hole = self.hole { + return HistoryPreloadHole(preloadIndex: self.preloadIndex, hole: hole) + } else { + return nil + } + } + + init(index: ChatListIndex?, hasUnread: Bool?, isMuted: Bool?, isPriority: Bool) { + self.index = index + self.hasUnread = hasUnread + self.isMuted = isMuted + self.isPriority = isPriority + } + + deinit { + disposable.dispose() + } +} + +private enum ChatHistoryPreloadEntity: Hashable { + case peer(PeerId) + //case group(PeerGroupId) +} + +private struct ChatHistoryPreloadIndex { + let index: ChatListIndex + let entity: ChatHistoryPreloadEntity +} + +public final class ChatHistoryPreloadMediaItem: Comparable { + public let preloadIndex: HistoryPreloadIndex + public let media: HolesViewMedia + + init(preloadIndex: HistoryPreloadIndex, media: HolesViewMedia) { + self.preloadIndex = preloadIndex + self.media = media + } + + public static func ==(lhs: ChatHistoryPreloadMediaItem, rhs: ChatHistoryPreloadMediaItem) -> Bool { + if lhs.preloadIndex != rhs.preloadIndex { + return false + } + if lhs.media != rhs.media { + return false + } + return true + } + + public static func <(lhs: ChatHistoryPreloadMediaItem, rhs: ChatHistoryPreloadMediaItem) -> Bool { + if lhs.preloadIndex != rhs.preloadIndex { + return lhs.preloadIndex > rhs.preloadIndex + } + return lhs.media.index < rhs.media.index + } +} + +private final class AdditionalPreloadPeerIdsContext { + private let queue: Queue + + private var subscribers: [PeerId: Bag] = [:] + private var additionalPeerIdsValue = ValuePromise>(Set(), ignoreRepeated: true) + + var additionalPeerIds: Signal, NoError> { + return self.additionalPeerIdsValue.get() + } + + init(queue: Queue) { + self.queue = queue + } + + deinit { + assert(self.queue.isCurrent()) + } + + func add(peerId: PeerId) -> Disposable { + let bag: Bag + if let current = self.subscribers[peerId] { + bag = current + } else { + bag = Bag() + self.subscribers[peerId] = bag + } + let wasEmpty = bag.isEmpty + let index = bag.add(Void()) + + if wasEmpty { + self.additionalPeerIdsValue.set(Set(self.subscribers.keys)) + } + let queue = self.queue + return ActionDisposable { [weak self, weak bag] in + queue.async { + guard let strongSelf = self else { + return + } + if let current = strongSelf.subscribers[peerId], let bag = bag, current === bag { + current.remove(index) + if current.isEmpty { + strongSelf.subscribers.removeValue(forKey: peerId) + strongSelf.additionalPeerIdsValue.set(Set(strongSelf.subscribers.keys)) + } + } + } + } + } +} + +final class ChatHistoryPreloadManager { + private let queue = Queue() + + private let postbox: Postbox + private let accountPeerId: PeerId + private let network: Network + private let download = Promise() + + private var canPreloadHistoryDisposable: Disposable? + private var canPreloadHistoryValue = false + + private let automaticChatListDisposable = MetaDisposable() + + private var views: [ChatHistoryPreloadEntity: HistoryPreloadViewContext] = [:] + + private var entries: [HistoryPreloadEntry] = [] + + private var orderedMediaValue: [ChatHistoryPreloadMediaItem] = [] + private let orderedMediaPromise = ValuePromise<[ChatHistoryPreloadMediaItem]>([]) + var orderedMedia: Signal<[ChatHistoryPreloadMediaItem], NoError> { + return self.orderedMediaPromise.get() + } + + private let additionalPreloadPeerIdsContext: QueueLocalObject + + init(postbox: Postbox, network: Network, accountPeerId: PeerId, networkState: Signal) { + self.postbox = postbox + self.network = network + self.accountPeerId = accountPeerId + self.download.set(network.background()) + + let queue = Queue.mainQueue() + self.additionalPreloadPeerIdsContext = QueueLocalObject(queue: queue, generate: { + AdditionalPreloadPeerIdsContext(queue: queue) + }) + + self.canPreloadHistoryDisposable = (networkState + |> map { state -> Bool in + switch state { + case .online: + return true + default: + return false + } + } + |> distinctUntilChanged + |> deliverOn(self.queue)).start(next: { [weak self] value in + guard let strongSelf = self, strongSelf.canPreloadHistoryValue != value else { + return + } + strongSelf.canPreloadHistoryValue = value + if value { + for i in 0 ..< min(3, strongSelf.entries.count) { + strongSelf.entries[i].startIfNeeded(postbox: strongSelf.postbox, accountPeerId: strongSelf.accountPeerId, download: strongSelf.download.get() |> take(1), queue: strongSelf.queue) + } + } + }) + } + + deinit { + self.canPreloadHistoryDisposable?.dispose() + } + + func addAdditionalPeerId(peerId: PeerId) -> Disposable { + let disposable = MetaDisposable() + self.additionalPreloadPeerIdsContext.with { context in + disposable.set(context.add(peerId: peerId)) + } + return disposable + } + + func start() { + let additionalPreloadPeerIdsContext = self.additionalPreloadPeerIdsContext + let additionalPeerIds = Signal, NoError> { subscriber in + let disposable = MetaDisposable() + additionalPreloadPeerIdsContext.with { context in + disposable.set(context.additionalPeerIds.start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + self.automaticChatListDisposable.set((combineLatest(queue: .mainQueue(), postbox.tailChatListView(groupId: .root, count: 20, summaryComponents: ChatListEntrySummaryComponents()), additionalPeerIds) + |> delay(1.0, queue: .mainQueue()) + |> deliverOnMainQueue).start(next: { [weak self] view, additionalPeerIds in + guard let strongSelf = self else { + return + } + #if DEBUG + //return; + #endif + var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = [] + for entry in view.0.entries { + if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _) = entry { + var hasUnread = false + if let readState = readState { + hasUnread = readState.count != 0 + } + var isMuted = false + if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { + if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { + isMuted = true + } + } + indices.append((ChatHistoryPreloadIndex(index: index, entity: .peer(index.messageIndex.id.peerId)), hasUnread, isMuted)) + } + } + + strongSelf.update(indices: indices, additionalPeerIds: additionalPeerIds) + })) + } + + private func update(indices: [(ChatHistoryPreloadIndex, Bool, Bool)], additionalPeerIds: Set) { + self.queue.async { + var validEntityIds = Set(indices.map { $0.0.entity }) + for peerId in additionalPeerIds { + validEntityIds.insert(.peer(peerId)) + } + + var removedEntityIds: [ChatHistoryPreloadEntity] = [] + for (entityId, view) in self.views { + if !validEntityIds.contains(entityId) { + removedEntityIds.append(entityId) + if let hole = view.currentHole { + self.update(from: hole, to: nil) + } + } + } + for entityId in removedEntityIds { + self.views.removeValue(forKey: entityId) + } + + var combinedIndices: [(ChatHistoryPreloadIndex, Bool, Bool, Bool)] = [] + var existingPeerIds = Set() + for (index, hasUnread, isMuted) in indices { + existingPeerIds.insert(index.index.messageIndex.id.peerId) + combinedIndices.append((index, hasUnread, isMuted, additionalPeerIds.contains(index.index.messageIndex.id.peerId))) + } + for peerId in additionalPeerIds { + if !existingPeerIds.contains(peerId) { + combinedIndices.append((ChatHistoryPreloadIndex(index: ChatListIndex.absoluteLowerBound, entity: .peer(peerId)), false, true, true)) + } + } + + for (index, hasUnread, isMuted, isPriority) in combinedIndices { + if let view = self.views[index.entity] { + if view.index != index.index || view.hasUnread != hasUnread || view.isMuted != isMuted { + let previousHole = view.currentHole + view.index = index.index + view.hasUnread = hasUnread + view.isMuted = isMuted + + let updatedHole = view.currentHole + if previousHole != updatedHole { + self.update(from: previousHole, to: updatedHole) + } + } + } else { + let view = HistoryPreloadViewContext(index: index.index, hasUnread: hasUnread, isMuted: isMuted, isPriority: isPriority) + self.views[index.entity] = view + let key: PostboxViewKey + switch index.entity { + case let .peer(peerId): + key = .messageOfInterestHole(location: .peer(peerId), namespace: Namespaces.Message.Cloud, count: 60) + } + view.disposable.set((self.postbox.combinedView(keys: [key]) + |> deliverOn(self.queue)).start(next: { [weak self] next in + if let strongSelf = self, let value = next.views[key] as? MessageOfInterestHolesView { + if let view = strongSelf.views[index.entity] { + let previousHole = view.currentHole + view.hole = value.closestHole + + var mediaUpdated = false + if view.media.count != value.closestLaterMedia.count { + mediaUpdated = true + } else { + for i in 0 ..< view.media.count { + if view.media[i] != value.closestLaterMedia[i] { + mediaUpdated = true + break + } + } + } + if mediaUpdated { + view.media = value.closestLaterMedia + strongSelf.updateMedia() + } + + let updatedHole = view.currentHole + if previousHole != updatedHole { + strongSelf.update(from: previousHole, to: updatedHole) + } + } + } + })) + } + } + } + } + + private func updateMedia() { + var result: [ChatHistoryPreloadMediaItem] = [] + for (_, view) in self.views { + for media in view.media { + result.append(ChatHistoryPreloadMediaItem(preloadIndex: view.preloadIndex, media: media)) + } + } + result.sort() + if result != self.orderedMediaValue { + self.orderedMediaValue = result + self.orderedMediaPromise.set(result) + } + } + + private func update(from previousHole: HistoryPreloadHole?, to updatedHole: HistoryPreloadHole?) { + assert(self.queue.isCurrent()) + if previousHole == updatedHole { + return + } + + var skipUpdated = false + if let previousHole = previousHole { + for i in (0 ..< self.entries.count).reversed() { + if self.entries[i].hole == previousHole { + if let updatedHole = updatedHole, updatedHole.hole == self.entries[i].hole.hole { + self.entries[i].hole = updatedHole + skipUpdated = true + } else { + self.entries.remove(at: i) + } + break + } + } + } + + if let updatedHole = updatedHole, !skipUpdated { + var found = false + for i in 0 ..< self.entries.count { + if self.entries[i].hole == updatedHole { + found = true + break + } + } + if !found { + self.entries.append(HistoryPreloadEntry(hole: updatedHole)) + self.entries.sort() + } + } + + if self.canPreloadHistoryValue { + for i in 0 ..< min(3, self.entries.count) { + self.entries[i].startIfNeeded(postbox: self.postbox, accountPeerId: self.accountPeerId, download: self.download.get() |> take(1), queue: self.queue) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ChatOnlineMembers.swift b/submodules/TelegramCore/TelegramCore/ChatOnlineMembers.swift new file mode 100644 index 0000000000..bd174f6a3d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ChatOnlineMembers.swift @@ -0,0 +1,29 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public func chatOnlineMembers(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .single(0) + } + return network.request(Api.functions.messages.getOnlines(peer: inputPeer)) + |> map { value -> Int32 in + switch value { + case let .chatOnlines(onlines): + return onlines + } + } + |> `catch` { _ -> Signal in + return .single(0) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/CheckPeerChatServiceActions.swift b/submodules/TelegramCore/TelegramCore/CheckPeerChatServiceActions.swift new file mode 100644 index 0000000000..3cb76a539b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CheckPeerChatServiceActions.swift @@ -0,0 +1,23 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func checkPeerChatServiceActions(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.applyMarkUnread(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, value: false, interactive: true) + + if peerId.namespace == Namespaces.Peer.SecretChat { + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + let updatedState = secretChatCheckLayerNegotiationIfNeeded(transaction: transaction, peerId: peerId, state: state) + if state != updatedState { + transaction.setPeerChatState(peerId, state: updatedState) + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ClearCloudDrafts.swift b/submodules/TelegramCore/TelegramCore/ClearCloudDrafts.swift new file mode 100644 index 0000000000..84fc54d390 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ClearCloudDrafts.swift @@ -0,0 +1,76 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public func clearCloudDraftsInteractively(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal { + return network.request(Api.functions.messages.getAllDrafts()) + |> retryRequest + |> mapToSignal { updates -> Signal in + return postbox.transaction { transaction -> Signal in + var peerIds = Set() + switch updates { + case let .updates(updates, users, chats, _, _): + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + for update in updates { + switch update { + case let .updateDraftMessage(peer, _): + peerIds.insert(peer.peerId) + default: + break + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + var signals: [Signal] = [] + for peerId in peerIds { + transaction.updatePeerChatInterfaceState(peerId, update: { current in + if let current = current as? SynchronizeableChatInterfaceState { + return current.withUpdatedSynchronizeableInputState(nil) + } else { + return nil + } + }) + + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + signals.append(network.request(Api.functions.messages.saveDraft(flags: 0, replyToMsgId: nil, peer: inputPeer, message: "", entities: nil)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + }) + } + } + + return combineLatest(signals) + |> mapToSignal { _ -> Signal in + return .complete() + } + default: + break + } + return .complete() + } |> switchToLatest + } +} diff --git a/submodules/TelegramCore/TelegramCore/CloudChatRemoveMessagesOperation.swift b/submodules/TelegramCore/TelegramCore/CloudChatRemoveMessagesOperation.swift new file mode 100644 index 0000000000..c04b940624 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CloudChatRemoveMessagesOperation.swift @@ -0,0 +1,130 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +enum CloudChatRemoveMessagesType: Int32 { + case forLocalPeer + case forEveryone +} + +extension CloudChatRemoveMessagesType { + init(_ type: InteractiveMessagesDeletionType) { + switch type { + case .forLocalPeer: + self = .forLocalPeer + case .forEveryone: + self = .forEveryone + } + } +} + +final class CloudChatRemoveMessagesOperation: PostboxCoding { + let messageIds: [MessageId] + let type: CloudChatRemoveMessagesType + + init(messageIds: [MessageId], type: CloudChatRemoveMessagesType) { + self.messageIds = messageIds + self.type = type + } + + init(decoder: PostboxDecoder) { + self.messageIds = MessageId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("i")!) + self.type = CloudChatRemoveMessagesType(rawValue: decoder.decodeInt32ForKey("t", orElse: 0))! + } + + func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + MessageId.encodeArrayToBuffer(self.messageIds, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "i") + encoder.encodeInt32(self.type.rawValue, forKey: "t") + } +} + +final class CloudChatRemoveChatOperation: PostboxCoding { + let peerId: PeerId + let reportChatSpam: Bool + let deleteGloballyIfPossible: Bool + let topMessageId: MessageId? + + init(peerId: PeerId, reportChatSpam: Bool, deleteGloballyIfPossible: Bool, topMessageId: MessageId?) { + self.peerId = peerId + self.reportChatSpam = reportChatSpam + self.deleteGloballyIfPossible = deleteGloballyIfPossible + self.topMessageId = topMessageId + } + + init(decoder: PostboxDecoder) { + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.reportChatSpam = decoder.decodeInt32ForKey("r", orElse: 0) != 0 + self.deleteGloballyIfPossible = decoder.decodeInt32ForKey("deleteGloballyIfPossible", orElse: 0) != 0 + if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("m.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("m.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("m.i") { + self.topMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId) + } else { + self.topMessageId = nil + } + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.peerId.toInt64(), forKey: "p") + encoder.encodeInt32(self.reportChatSpam ? 1 : 0, forKey: "r") + encoder.encodeInt32(self.deleteGloballyIfPossible ? 1 : 0, forKey: "deleteGloballyIfPossible") + if let topMessageId = self.topMessageId { + encoder.encodeInt64(topMessageId.peerId.toInt64(), forKey: "m.p") + encoder.encodeInt32(topMessageId.namespace, forKey: "m.n") + encoder.encodeInt32(topMessageId.id, forKey: "m.i") + } else { + encoder.encodeNil(forKey: "m.p") + encoder.encodeNil(forKey: "m.n") + encoder.encodeNil(forKey: "m.i") + } + } +} + +final class CloudChatClearHistoryOperation: PostboxCoding { + let peerId: PeerId + let topMessageId: MessageId + let type: InteractiveMessagesDeletionType + + init(peerId: PeerId, topMessageId: MessageId, type: InteractiveMessagesDeletionType) { + self.peerId = peerId + self.topMessageId = topMessageId + self.type = type + } + + init(decoder: PostboxDecoder) { + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)) + self.type = InteractiveMessagesDeletionType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.peerId.toInt64(), forKey: "p") + encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p") + encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n") + encoder.encodeInt32(self.topMessageId.id, forKey: "m.i") + encoder.encodeInt32(self.type.rawValue, forKey: "type") + } +} + +func cloudChatAddRemoveMessagesOperation(transaction: Transaction, peerId: PeerId, messageIds: [MessageId], type: CloudChatRemoveMessagesType) { + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveMessagesOperation(messageIds: messageIds, type: type)) +} + +func cloudChatAddRemoveChatOperation(transaction: Transaction, peerId: PeerId, reportChatSpam: Bool, deleteGloballyIfPossible: Bool) { + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud))) +} + +func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: InteractiveMessagesDeletionType) { + let topMessageId: MessageId? + if let explicitTopMessageId = explicitTopMessageId { + topMessageId = explicitTopMessageId + } else { + topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) + } + if let topMessageId = topMessageId { + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type)) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CloudFileMediaResource.swift b/submodules/TelegramCore/TelegramCore/CloudFileMediaResource.swift new file mode 100644 index 0000000000..612b332703 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CloudFileMediaResource.swift @@ -0,0 +1,899 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +protocol TelegramCloudMediaResource: TelegramMediaResource { + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? +} + +protocol TelegramMultipartFetchableResource: TelegramMediaResource { + var datacenterId: Int { get } +} + +public struct CloudFileMediaResourceId: MediaResourceId { + let datacenterId: Int + let volumeId: Int64 + let localId: Int32 + let secret: Int64 + + init(datacenterId: Int, volumeId: Int64, localId: Int32, secret: Int64) { + self.datacenterId = datacenterId + self.volumeId = volumeId + self.localId = localId + self.secret = secret + } + + public var uniqueId: String { + return "telegram-cloud-file-\(self.datacenterId)-\(self.volumeId)-\(self.localId)-\(self.secret)" + } + + public var hashValue: Int { + return self.secret.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudFileMediaResourceId { + return self.datacenterId == to.datacenterId && self.volumeId == to.volumeId && self.localId == to.localId && self.secret == to.secret + } else { + return false + } + } +} + +public protocol TelegramCloudMediaResourceWithFileReference { + var fileReference: Data? { get } +} + +public class CloudFileMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource, TelegramCloudMediaResourceWithFileReference { + public let datacenterId: Int + public let volumeId: Int64 + public let localId: Int32 + public let secret: Int64 + public let size: Int? + public let fileReference: Data? + + public var id: MediaResourceId { + return CloudFileMediaResourceId(datacenterId: self.datacenterId, volumeId: self.volumeId, localId: self.localId, secret: self.secret) + } + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputFileLocation(volumeId: self.volumeId, localId: self.localId, secret: self.secret, fileReference: Buffer(data: fileReference ?? Data())) + } + + public init(datacenterId: Int, volumeId: Int64, localId: Int32, secret: Int64, size: Int?, fileReference: Data?) { + self.datacenterId = datacenterId + self.volumeId = volumeId + self.localId = localId + self.secret = secret + self.size = size + self.fileReference = fileReference + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + self.secret = decoder.decodeInt64ForKey("s", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("n") { + self.size = Int(size) + } else { + self.size = nil + } + self.fileReference = decoder.decodeBytesForKey("fr")?.makeData() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt64(self.volumeId, forKey: "v") + encoder.encodeInt32(self.localId, forKey: "l") + encoder.encodeInt64(self.secret, forKey: "s") + if let size = self.size { + encoder.encodeInt32(Int32(size), forKey: "n") + } else { + encoder.encodeNil(forKey: "n") + } + if let fileReference = self.fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudFileMediaResource { + return self.datacenterId == to.datacenterId && self.volumeId == to.volumeId && self.localId == to.localId && self.secret == to.secret && self.size == to.size && self.fileReference == to.fileReference + } else { + return false + } + } +} + +public struct CloudPhotoSizeMediaResourceId: MediaResourceId, Hashable { + let datacenterId: Int32 + let photoId: Int64 + let sizeSpec: String + + init(datacenterId: Int32, photoId: Int64, sizeSpec: String) { + self.datacenterId = datacenterId + self.photoId = photoId + self.sizeSpec = sizeSpec + } + + public var uniqueId: String { + return "telegram-cloud-photo-size-\(self.datacenterId)-\(self.photoId)-\(self.sizeSpec)" + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudPhotoSizeMediaResourceId { + return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.sizeSpec == to.sizeSpec + } else { + return false + } + } +} + +public class CloudPhotoSizeMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource, TelegramCloudMediaResourceWithFileReference { + public let datacenterId: Int + public let photoId: Int64 + public let accessHash: Int64 + public let sizeSpec: String + public let volumeId: Int64 + public let localId: Int32 + public let fileReference: Data? + + public var id: MediaResourceId { + return CloudPhotoSizeMediaResourceId(datacenterId: Int32(self.datacenterId), photoId: self.photoId, sizeSpec: self.sizeSpec) + } + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputPhotoFileLocation(id: self.photoId, accessHash: self.accessHash, fileReference: Buffer(data: fileReference ?? Data()), thumbSize: self.sizeSpec) + } + + public init(datacenterId: Int32, photoId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, fileReference: Data?) { + self.datacenterId = Int(datacenterId) + self.photoId = photoId + self.accessHash = accessHash + self.sizeSpec = sizeSpec + self.volumeId = volumeId + self.localId = localId + self.fileReference = fileReference + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.photoId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.sizeSpec = decoder.decodeStringForKey("s", orElse: "") + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + self.fileReference = decoder.decodeBytesForKey("fr")?.makeData() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt64(self.photoId, forKey: "i") + encoder.encodeInt64(self.accessHash, forKey: "h") + encoder.encodeString(self.sizeSpec, forKey: "s") + encoder.encodeInt64(self.volumeId, forKey: "v") + encoder.encodeInt32(self.localId, forKey: "l") + if let fileReference = self.fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudPhotoSizeMediaResource { + return self.datacenterId == to.datacenterId && self.photoId == to.photoId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.fileReference == to.fileReference + } else { + return false + } + } +} + +public struct CloudDocumentSizeMediaResourceId: MediaResourceId, Hashable { + let datacenterId: Int32 + let documentId: Int64 + let sizeSpec: String + + init(datacenterId: Int32, documentId: Int64, sizeSpec: String) { + self.datacenterId = datacenterId + self.documentId = documentId + self.sizeSpec = sizeSpec + } + + public var uniqueId: String { + return "telegram-cloud-document-size-\(self.datacenterId)-\(self.documentId)-\(self.sizeSpec)" + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudDocumentSizeMediaResourceId { + return self.datacenterId == to.datacenterId && self.documentId == to.documentId && self.sizeSpec == to.sizeSpec + } else { + return false + } + } +} + +public class CloudDocumentSizeMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource, TelegramCloudMediaResourceWithFileReference { + public let datacenterId: Int + public let documentId: Int64 + public let accessHash: Int64 + public let sizeSpec: String + public let volumeId: Int64 + public let localId: Int32 + public let fileReference: Data? + + public var id: MediaResourceId { + return CloudDocumentSizeMediaResourceId(datacenterId: Int32(self.datacenterId), documentId: self.documentId, sizeSpec: self.sizeSpec) + } + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputDocumentFileLocation(id: self.documentId, accessHash: self.accessHash, fileReference: Buffer(data: fileReference ?? Data()), thumbSize: self.sizeSpec) + } + + public init(datacenterId: Int32, documentId: Int64, accessHash: Int64, sizeSpec: String, volumeId: Int64, localId: Int32, fileReference: Data?) { + self.datacenterId = Int(datacenterId) + self.documentId = documentId + self.accessHash = accessHash + self.sizeSpec = sizeSpec + self.volumeId = volumeId + self.localId = localId + self.fileReference = fileReference + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.documentId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.sizeSpec = decoder.decodeStringForKey("s", orElse: "") + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + self.fileReference = decoder.decodeBytesForKey("fr")?.makeData() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt64(self.documentId, forKey: "i") + encoder.encodeInt64(self.accessHash, forKey: "h") + encoder.encodeString(self.sizeSpec, forKey: "s") + encoder.encodeInt64(self.volumeId, forKey: "v") + encoder.encodeInt32(self.localId, forKey: "l") + if let fileReference = self.fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudDocumentSizeMediaResource { + return self.datacenterId == to.datacenterId && self.documentId == to.documentId && self.accessHash == to.accessHash && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId && self.fileReference == to.fileReference + } else { + return false + } + } +} + +public enum CloudPeerPhotoSizeSpec: Int32 { + case small + case fullSize +} + +public struct CloudPeerPhotoSizeMediaResourceId: MediaResourceId, Hashable { + let datacenterId: Int32 + let sizeSpec: CloudPeerPhotoSizeSpec + let volumeId: Int64 + let localId: Int32 + + init(datacenterId: Int32, sizeSpec: CloudPeerPhotoSizeSpec, volumeId: Int64, localId: Int32) { + self.datacenterId = datacenterId + self.sizeSpec = sizeSpec + self.volumeId = volumeId + self.localId = localId + } + + public var uniqueId: String { + return "telegram-peer-photo-size-\(self.datacenterId)-\(self.sizeSpec.rawValue)-\(self.volumeId)-\(self.localId)" + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudPeerPhotoSizeMediaResourceId { + return self.datacenterId == to.datacenterId && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId + } else { + return false + } + } +} + +public class CloudPeerPhotoSizeMediaResource: TelegramMultipartFetchableResource { + public let datacenterId: Int + let sizeSpec: CloudPeerPhotoSizeSpec + let volumeId: Int64 + let localId: Int32 + + public var id: MediaResourceId { + return CloudPeerPhotoSizeMediaResourceId(datacenterId: Int32(self.datacenterId), sizeSpec: self.sizeSpec, volumeId: self.volumeId, localId: self.localId) + } + + func apiInputLocation(peerReference: PeerReference) -> Api.InputFileLocation? { + let flags: Int32 + switch self.sizeSpec { + case .small: + flags = 0 + case .fullSize: + flags = 1 << 0 + } + return Api.InputFileLocation.inputPeerPhotoFileLocation(flags: flags, peer: peerReference.inputPeer, volumeId: self.volumeId, localId: self.localId) + } + + public init(datacenterId: Int32, sizeSpec: CloudPeerPhotoSizeSpec, volumeId: Int64, localId: Int32) { + self.datacenterId = Int(datacenterId) + self.sizeSpec = sizeSpec + self.volumeId = volumeId + self.localId = localId + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.sizeSpec = CloudPeerPhotoSizeSpec(rawValue: decoder.decodeInt32ForKey("s", orElse: 0)) ?? .small + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt32(self.sizeSpec.rawValue, forKey: "s") + encoder.encodeInt64(self.volumeId, forKey: "v") + encoder.encodeInt32(self.localId, forKey: "l") + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudPeerPhotoSizeMediaResource { + return self.datacenterId == to.datacenterId && self.sizeSpec == to.sizeSpec && self.volumeId == to.volumeId && self.localId == to.localId + } else { + return false + } + } +} + +public struct CloudStickerPackThumbnailMediaResourceId: MediaResourceId, Hashable { + let datacenterId: Int32 + let volumeId: Int64 + let localId: Int32 + + init(datacenterId: Int32, volumeId: Int64, localId: Int32) { + self.datacenterId = datacenterId + self.volumeId = volumeId + self.localId = localId + } + + public var uniqueId: String { + return "telegram-stickerpackthumbnail-\(self.datacenterId)-\(self.volumeId)-\(self.localId)" + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudStickerPackThumbnailMediaResourceId { + return self.datacenterId == to.datacenterId && self.volumeId == to.volumeId && self.localId == to.localId + } else { + return false + } + } +} + +public class CloudStickerPackThumbnailMediaResource: TelegramMultipartFetchableResource { + public let datacenterId: Int + let volumeId: Int64 + let localId: Int32 + + public var id: MediaResourceId { + return CloudStickerPackThumbnailMediaResourceId(datacenterId: Int32(self.datacenterId), volumeId: self.volumeId, localId: self.localId) + } + + func apiInputLocation(packReference: StickerPackReference) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputStickerSetThumb(stickerset: packReference.apiInputStickerSet, volumeId: self.volumeId, localId: self.localId) + } + + public init(datacenterId: Int32, volumeId: Int64, localId: Int32) { + self.datacenterId = Int(datacenterId) + self.volumeId = volumeId + self.localId = localId + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.volumeId = decoder.decodeInt64ForKey("v", orElse: 0) + self.localId = decoder.decodeInt32ForKey("l", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt64(self.volumeId, forKey: "v") + encoder.encodeInt32(self.localId, forKey: "l") + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudPeerPhotoSizeMediaResource { + return self.datacenterId == to.datacenterId && self.volumeId == to.volumeId && self.localId == to.localId + } else { + return false + } + } +} + +public struct CloudDocumentMediaResourceId: MediaResourceId { + let datacenterId: Int + let fileId: Int64 + + init(datacenterId: Int, fileId: Int64) { + self.datacenterId = datacenterId + self.fileId = fileId + } + + public var uniqueId: String { + return "telegram-cloud-document-\(self.datacenterId)-\(self.fileId)" + } + + public var hashValue: Int { + return self.fileId.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? CloudDocumentMediaResourceId { + return self.datacenterId == to.datacenterId && self.fileId == to.fileId + } else { + return false + } + } +} + +public class CloudDocumentMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource, TelegramCloudMediaResourceWithFileReference { + public let datacenterId: Int + public let fileId: Int64 + public let accessHash: Int64 + public let size: Int? + public let fileReference: Data? + public let fileName: String? + + public var id: MediaResourceId { + return CloudDocumentMediaResourceId(datacenterId: self.datacenterId, fileId: self.fileId) + } + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputDocumentFileLocation(id: self.fileId, accessHash: self.accessHash, fileReference: Buffer(data: fileReference ?? Data()), thumbSize: "") + } + + public init(datacenterId: Int, fileId: Int64, accessHash: Int64, size: Int?, fileReference: Data?, fileName: String?) { + self.datacenterId = datacenterId + self.fileId = fileId + self.accessHash = accessHash + self.size = size + self.fileReference = fileReference + self.fileName = fileName + } + + public required init(decoder: PostboxDecoder) { + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.fileId = decoder.decodeInt64ForKey("f", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("n") { + self.size = Int(size) + } else { + self.size = nil + } + self.fileReference = decoder.decodeBytesForKey("fr")?.makeData() + self.fileName = decoder.decodeOptionalStringForKey("fn") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeInt64(self.fileId, forKey: "f") + encoder.encodeInt64(self.accessHash, forKey: "a") + if let size = self.size { + encoder.encodeInt32(Int32(size), forKey: "n") + } else { + encoder.encodeNil(forKey: "n") + } + if let fileReference = self.fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + if let fileName = self.fileName { + encoder.encodeString(fileName, forKey: "fn") + } else { + encoder.encodeNil(forKey: "fn") + } + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? CloudDocumentMediaResource { + return self.datacenterId == to.datacenterId && self.fileId == to.fileId && self.accessHash == to.accessHash && self.size == to.size && self.fileReference == to.fileReference + } else { + return false + } + } +} + +public struct LocalFileMediaResourceId: MediaResourceId { + public let fileId: Int64 + + public var uniqueId: String { + return "telegram-local-file-\(self.fileId)" + } + + public var hashValue: Int { + return self.fileId.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? LocalFileMediaResourceId { + return self.fileId == to.fileId + } else { + return false + } + } +} + +public class LocalFileMediaResource: TelegramMediaResource { + public let fileId: Int64 + public let size: Int? + + public init(fileId: Int64, size: Int? = nil) { + self.fileId = fileId + self.size = size + } + + public required init(decoder: PostboxDecoder) { + self.fileId = decoder.decodeInt64ForKey("f", orElse: 0) + if let size = decoder.decodeOptionalInt32ForKey("s") { + self.size = Int(size) + } else { + self.size = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.fileId, forKey: "f") + if let size = self.size { + encoder.encodeInt32(Int32(size), forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + } + + public var id: MediaResourceId { + return LocalFileMediaResourceId(fileId: self.fileId) + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? LocalFileMediaResource { + return self.fileId == to.fileId && self.size == to.size + } else { + return false + } + } +} + +public struct LocalFileReferenceMediaResourceId: MediaResourceId { + public let randomId: Int64 + + public var uniqueId: String { + return "local-file-\(self.randomId)" + } + + public var hashValue: Int { + return self.randomId.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? LocalFileReferenceMediaResourceId { + return self.randomId == to.randomId + } else { + return false + } + } +} + +public class LocalFileReferenceMediaResource: TelegramMediaResource { + public let localFilePath: String + let randomId: Int64 + let isUniquelyReferencedTemporaryFile: Bool + public let size: Int32? + + public init(localFilePath: String, randomId: Int64, isUniquelyReferencedTemporaryFile: Bool = false, size: Int32? = nil) { + self.localFilePath = localFilePath + self.randomId = randomId + self.isUniquelyReferencedTemporaryFile = isUniquelyReferencedTemporaryFile + self.size = size + } + + public required init(decoder: PostboxDecoder) { + self.localFilePath = decoder.decodeStringForKey("p", orElse: "") + self.randomId = decoder.decodeInt64ForKey("r", orElse: 0) + self.isUniquelyReferencedTemporaryFile = decoder.decodeInt32ForKey("t", orElse: 0) != 0 + self.size = decoder.decodeOptionalInt32ForKey("s") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.localFilePath, forKey: "p") + encoder.encodeInt64(self.randomId, forKey: "r") + encoder.encodeInt32(self.isUniquelyReferencedTemporaryFile ? 1 : 0, forKey: "t") + if let size = self.size { + encoder.encodeInt32(size, forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + } + + public var id: MediaResourceId { + return LocalFileReferenceMediaResourceId(randomId: self.randomId) + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? LocalFileReferenceMediaResource { + return self.localFilePath == to.localFilePath && self.randomId == to.randomId && self.size == to.size && self.isUniquelyReferencedTemporaryFile == to.isUniquelyReferencedTemporaryFile + } else { + return false + } + } +} + +public struct HttpReferenceMediaResourceId: MediaResourceId { + public let url: String + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? HttpReferenceMediaResourceId { + return self.url == to.url + } else { + return false + } + } + + public var hashValue: Int { + return self.url.hashValue + } + + public var uniqueId: String { + return "http-\(persistentHash32(self.url))" + } +} + +public final class HttpReferenceMediaResource: TelegramMediaResource { + public let url: String + public let size: Int? + + public init(url: String, size: Int?) { + self.url = url + self.size = size + } + + public required init(decoder: PostboxDecoder) { + self.url = decoder.decodeStringForKey("u", orElse: "") + if let size = decoder.decodeOptionalInt32ForKey("s") { + self.size = Int(size) + } else { + self.size = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.url, forKey: "u") + if let size = self.size { + encoder.encodeInt32(Int32(size), forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + } + + public var id: MediaResourceId { + return HttpReferenceMediaResourceId(url: self.url) + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? HttpReferenceMediaResource { + return to.url == self.url + } else { + return false + } + } +} + +public struct WebFileReferenceMediaResourceId: MediaResourceId { + public let url: String + public let accessHash: Int64 + public let size: Int32 + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? WebFileReferenceMediaResourceId { + return self.url == to.url && size == to.size && accessHash == to.accessHash + } else { + return false + } + } + + public var hashValue: Int { + return self.url.hashValue + } + + public var uniqueId: String { + return "proxy-\(persistentHash32(self.url))-\(size)-\(accessHash)" + } +} + +public final class WebFileReferenceMediaResource: TelegramMediaResource { + public let url: String + public let size: Int32 + public let accessHash: Int64 + + public init(url: String, size: Int32, accessHash: Int64) { + self.url = url + self.size = size + self.accessHash = accessHash + } + + var apiInputLocation: Api.InputWebFileLocation { + return Api.InputWebFileLocation.inputWebFileLocation(url: url, accessHash: accessHash) + } + + public required init(decoder: PostboxDecoder) { + self.url = decoder.decodeStringForKey("u", orElse: "") + self.size = decoder.decodeInt32ForKey("s", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.url, forKey: "u") + encoder.encodeInt32(self.size, forKey: "s") + encoder.encodeInt64(self.accessHash, forKey: "h") + } + + public var id: MediaResourceId { + return WebFileReferenceMediaResourceId(url: self.url, accessHash: accessHash, size: self.size) + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? WebFileReferenceMediaResource { + return to.url == self.url && to.size == self.size && to.accessHash == self.accessHash + } else { + return false + } + } +} + + +public struct SecretFileMediaResourceId: MediaResourceId { + public let fileId: Int64 + public let datacenterId: Int32 + + public var uniqueId: String { + return "secret-file-\(self.fileId)-\(self.datacenterId)" + } + + public init(fileId: Int64, datacenterId: Int32) { + self.fileId = fileId + self.datacenterId = datacenterId + } + + public var hashValue: Int { + return self.fileId.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? SecretFileMediaResourceId { + return self.fileId == to.fileId && self.datacenterId == to.datacenterId + } else { + return false + } + } +} + +public struct SecretFileMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource { + public let fileId: Int64 + public let accessHash: Int64 + public var size: Int? { + return Int(self.decryptedSize) + } + public let containerSize: Int32 + public let decryptedSize: Int32 + public let datacenterId: Int + public let key: SecretFileEncryptionKey + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return .inputEncryptedFileLocation(id: self.fileId, accessHash: self.accessHash) + } + + public init(fileId: Int64, accessHash: Int64, containerSize: Int32, decryptedSize: Int32, datacenterId: Int, key: SecretFileEncryptionKey) { + self.fileId = fileId + self.accessHash = accessHash + self.containerSize = containerSize + self.decryptedSize = decryptedSize + self.datacenterId = datacenterId + self.key = key + } + + public init(decoder: PostboxDecoder) { + self.fileId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + self.containerSize = decoder.decodeInt32ForKey("s", orElse: 0) + self.decryptedSize = decoder.decodeInt32ForKey("ds", orElse: 0) + self.datacenterId = Int(decoder.decodeInt32ForKey("d", orElse: 0)) + self.key = decoder.decodeObjectForKey("k", decoder: { SecretFileEncryptionKey(decoder: $0) }) as! SecretFileEncryptionKey + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.fileId, forKey: "i") + encoder.encodeInt64(self.accessHash, forKey: "a") + encoder.encodeInt32(self.containerSize, forKey: "s") + encoder.encodeInt32(self.decryptedSize, forKey: "ds") + encoder.encodeInt32(Int32(self.datacenterId), forKey: "d") + encoder.encodeObject(self.key, forKey: "k") + } + + public var id: MediaResourceId { + return SecretFileMediaResourceId(fileId: self.fileId, datacenterId: Int32(self.datacenterId)) + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? SecretFileMediaResource { + if self.fileId != to.fileId { + return false + } + if self.accessHash != to.accessHash { + return false + } + if self.containerSize != to.containerSize { + return false + } + if self.decryptedSize != to.decryptedSize { + return false + } + if self.datacenterId != to.datacenterId { + return false + } + if self.key != to.key { + return false + } + return true + } else { + return false + } + } +} + +public struct EmptyMediaResourceId: MediaResourceId { + public var uniqueId: String { + return "empty-resource" + } + + public var hashValue: Int { + return 0 + } + + public func isEqual(to: MediaResourceId) -> Bool { + return to is EmptyMediaResourceId + } +} + +public final class EmptyMediaResource: TelegramMediaResource { + public init() { + } + + public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } + + public var id: MediaResourceId { + return EmptyMediaResourceId() + } + + public func isEqual(to: MediaResource) -> Bool { + return to is EmptyMediaResource + } +} diff --git a/submodules/TelegramCore/TelegramCore/CloudMediaResourceParameters.swift b/submodules/TelegramCore/TelegramCore/CloudMediaResourceParameters.swift new file mode 100644 index 0000000000..e9e165bf24 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CloudMediaResourceParameters.swift @@ -0,0 +1,8 @@ +import Foundation + +public enum CloudMediaResourceLocation: Equatable { + case photo(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String) + case file(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String) + case peerPhoto(peer: PeerReference, fullSize: Bool, volumeId: Int64, localId: Int64) + case stickerPackThumbnail(packReference: StickerPackReference, volumeId: Int64, localId: Int64) +} diff --git a/submodules/TelegramCore/TelegramCore/CollectCacheUsageStats.swift b/submodules/TelegramCore/TelegramCore/CollectCacheUsageStats.swift new file mode 100644 index 0000000000..699893259a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CollectCacheUsageStats.swift @@ -0,0 +1,271 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum PeerCacheUsageCategory: Int32 { + case image = 0 + case video + case audio + case file +} + +public struct CacheUsageStats { + public let media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]] + public let mediaResourceIds: [MediaId: [MediaResourceId]] + public let peers: [PeerId: Peer] + public let otherSize: Int64 + public let otherPaths: [String] + public let cacheSize: Int64 + public let tempPaths: [String] + public let tempSize: Int64 + public let immutableSize: Int64 + + public init(media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], mediaResourceIds: [MediaId: [MediaResourceId]], peers: [PeerId: Peer], otherSize: Int64, otherPaths: [String], cacheSize: Int64, tempPaths: [String], tempSize: Int64, immutableSize: Int64) { + self.media = media + self.mediaResourceIds = mediaResourceIds + self.peers = peers + self.otherSize = otherSize + self.otherPaths = otherPaths + self.cacheSize = cacheSize + self.tempPaths = tempPaths + self.tempSize = tempSize + self.immutableSize = immutableSize + } +} + +public enum CacheUsageStatsResult { + case progress(Float) + case result(CacheUsageStats) +} + +private enum CollectCacheUsageStatsError { + case done(CacheUsageStats) + case generic +} + +private final class CacheUsageStatsState { + var media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]] = [:] + var mediaResourceIds: [MediaId: [MediaResourceId]] = [:] + var allResourceIds = Set() + var lowerBound: MessageIndex? +} + +public func collectCacheUsageStats(account: Account, additionalCachePaths: [String], logFilesPath: String) -> Signal { + let state = Atomic(value: CacheUsageStatsState()) + + let excludeResourceIds = account.postbox.transaction { transaction -> Set in + var result = Set() + transaction.enumeratePreferencesEntries({ entry in + result.formUnion(entry.relatedResources.map(WrappedMediaResourceId.init)) + return true + }) + return result + } + + return excludeResourceIds + |> mapToSignal { excludeResourceIds -> Signal in + let fetch = account.postbox.transaction { transaction -> ([PeerId : Set], [MediaId : Media], MessageIndex?) in + return transaction.enumerateMedia(lowerBound: state.with { $0.lowerBound }, limit: 1000) + } + |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + + let process: ([PeerId : Set], [MediaId : Media], MessageIndex?) -> Signal = { mediaByPeer, mediaRefs, updatedLowerBound in + var mediaIdToPeerId: [MediaId: PeerId] = [:] + for (peerId, mediaIds) in mediaByPeer { + for id in mediaIds { + mediaIdToPeerId[id] = peerId + } + } + + var resourceIdToMediaId: [WrappedMediaResourceId: (MediaId, PeerCacheUsageCategory)] = [:] + var mediaResourceIds: [MediaId: [MediaResourceId]] = [:] + var resourceIds: [MediaResourceId] = [] + for (id, media) in mediaRefs { + mediaResourceIds[id] = [] + var parsedMedia: [Media] = [] + switch media { + case let image as TelegramMediaImage: + parsedMedia.append(image) + case let file as TelegramMediaFile: + parsedMedia.append(file) + case let webpage as TelegramMediaWebpage: + if case let .Loaded(content) = webpage.content { + if let image = content.image { + parsedMedia.append(image) + } + if let file = content.file { + parsedMedia.append(file) + } + } + default: + break + } + for media in parsedMedia { + if let image = media as? TelegramMediaImage { + for representation in image.representations { + resourceIds.append(representation.resource.id) + resourceIdToMediaId[WrappedMediaResourceId(representation.resource.id)] = (id, .image) + mediaResourceIds[id]!.append(representation.resource.id) + } + } else if let file = media as? TelegramMediaFile { + var category: PeerCacheUsageCategory = .file + loop: for attribute in file.attributes { + switch attribute { + case .Video: + category = .video + break loop + case .Audio: + category = .audio + break loop + default: + break + } + } + for representation in file.previewRepresentations { + resourceIds.append(representation.resource.id) + resourceIdToMediaId[WrappedMediaResourceId(representation.resource.id)] = (id, category) + mediaResourceIds[id]!.append(representation.resource.id) + } + resourceIds.append(file.resource.id) + resourceIdToMediaId[WrappedMediaResourceId(file.resource.id)] = (id, category) + mediaResourceIds[id]!.append(file.resource.id) + } + } + } + return account.postbox.mediaBox.collectResourceCacheUsage(resourceIds) + |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + |> mapToSignal { result -> Signal in + state.with { state -> Void in + state.lowerBound = updatedLowerBound + for (wrappedId, size) in result { + if let (id, category) = resourceIdToMediaId[wrappedId] { + if let peerId = mediaIdToPeerId[id] { + if state.media[peerId] == nil { + state.media[peerId] = [:] + } + if state.media[peerId]![category] == nil { + state.media[peerId]![category] = [:] + } + var currentSize: Int64 = 0 + if let current = state.media[peerId]![category]![id] { + currentSize = current + } + state.media[peerId]![category]![id] = currentSize + size + } + } + } + for (id, ids) in mediaResourceIds { + state.mediaResourceIds[id] = ids + for resourceId in ids { + state.allResourceIds.insert(WrappedMediaResourceId(resourceId)) + } + } + } + if updatedLowerBound == nil { + let (finalMedia, finalMediaResourceIds, allResourceIds) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set) in + return (state.media, state.mediaResourceIds, state.allResourceIds) + } + + return account.postbox.mediaBox.collectOtherResourceUsage(excludeIds: excludeResourceIds, combinedExcludeIds: allResourceIds.union(excludeResourceIds)) + |> mapError { _ in return CollectCacheUsageStatsError.generic } + |> mapToSignal { otherSize, otherPaths, cacheSize in + var tempPaths: [String] = [] + var tempSize: Int64 = 0 + #if os(iOS) + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: NSTemporaryDirectory()), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { + for url in enumerator { + if let url = url as? URL { + if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { + tempPaths.append(url.path) + } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { + tempPaths.append(url.path) + + if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { + } else { + tempSize += Int64(fileSizeValue) + } + } + } + } + } + #endif + + var immutableSize: Int64 = 0 + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: account.basePath + "/postbox/db"), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { + for url in files { + if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { + immutableSize += Int64(fileSize) + } + } + } + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logFilesPath), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { + for url in files { + if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { + immutableSize += Int64(fileSize) + } + } + } + + for additionalPath in additionalCachePaths { + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: additionalPath), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { + for url in enumerator { + if let url = url as? URL { + if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { + } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { + tempPaths.append(url.path) + + if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { + } else { + tempSize += Int64(fileSizeValue) + } + } + } + } + } + } + + return account.postbox.transaction { transaction -> CacheUsageStats in + var peers: [PeerId: Peer] = [:] + for peerId in finalMedia.keys { + if let peer = transaction.getPeer(peerId) { + peers[peer.id] = peer + if let associatedPeerId = peer.associatedPeerId, let associatedPeer = transaction.getPeer(associatedPeerId) { + peers[associatedPeer.id] = associatedPeer + } + } + } + return CacheUsageStats(media: finalMedia, mediaResourceIds: finalMediaResourceIds, peers: peers, otherSize: otherSize, otherPaths: otherPaths, cacheSize: cacheSize, tempPaths: tempPaths, tempSize: tempSize, immutableSize: immutableSize) + } |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + |> mapToSignal { stats -> Signal in + return .fail(.done(stats)) + } + } + } else { + return .complete() + } + } + } + + let signal = (fetch |> mapToSignal { mediaByPeer, mediaRefs, updatedLowerBound -> Signal in + return process(mediaByPeer, mediaRefs, updatedLowerBound) + }) |> restart + + return signal |> `catch` { error in + switch error { + case let .done(result): + return .single(.result(result)) + case .generic: + return .complete() + } + } + } +} + +public func clearCachedMediaResources(account: Account, mediaResourceIds: Set) -> Signal { + return account.postbox.mediaBox.removeCachedResources(mediaResourceIds) +} diff --git a/submodules/TelegramCore/TelegramCore/Config/TelegramCore.xcconfig b/submodules/TelegramCore/TelegramCore/Config/TelegramCore.xcconfig new file mode 100644 index 0000000000..c3b3ada1b4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Config/TelegramCore.xcconfig @@ -0,0 +1,2 @@ +SWIFT_INCLUDE_PATHS = $(SRCROOT)/TelegramCore +MODULEMAP_PRIVATE_FILE = $(SRCROOT)/TelegramCore/module.private.modulemap diff --git a/submodules/TelegramCore/TelegramCore/ConfirmTwoStepRecoveryEmail.swift b/submodules/TelegramCore/TelegramCore/ConfirmTwoStepRecoveryEmail.swift new file mode 100644 index 0000000000..3f0fa37428 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ConfirmTwoStepRecoveryEmail.swift @@ -0,0 +1,65 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import MtProtoKitMac +#else +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ConfirmTwoStepRecoveryEmailError { + case invalidEmail + case invalidCode + case flood + case expired + case generic +} + +public func confirmTwoStepRecoveryEmail(network: Network, code: String) -> Signal { + return network.request(Api.functions.account.confirmPasswordEmail(code: code), automaticFloodWait: false) + |> mapError { error -> ConfirmTwoStepRecoveryEmailError in + if error.errorDescription == "EMAIL_INVALID" { + return .invalidEmail + } else if error.errorDescription == "CODE_INVALID" { + return .invalidCode + } else if error.errorDescription == "EMAIL_HASH_EXPIRED" { + return .expired + } else if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } + return .generic + } + |> ignoreValues +} + +public enum ResendTwoStepRecoveryEmailError { + case flood + case generic +} + +public func resendTwoStepRecoveryEmail(network: Network) -> Signal { + return network.request(Api.functions.account.resendPasswordEmail(), automaticFloodWait: false) + |> mapError { error -> ResendTwoStepRecoveryEmailError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } + return .generic + } + |> ignoreValues +} + +public enum CancelTwoStepRecoveryEmailError { + case generic +} + +public func cancelTwoStepRecoveryEmail(network: Network) -> Signal { + return network.request(Api.functions.account.cancelPasswordEmail(), automaticFloodWait: false) + |> mapError { _ -> CancelTwoStepRecoveryEmailError in + return .generic + } + |> ignoreValues +} diff --git a/submodules/TelegramCore/TelegramCore/ConsumableContentMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ConsumableContentMessageAttribute.swift new file mode 100644 index 0000000000..029615a641 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ConsumableContentMessageAttribute.swift @@ -0,0 +1,22 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ConsumableContentMessageAttribute: MessageAttribute { + public let consumed: Bool + + public init(consumed: Bool) { + self.consumed = consumed + } + + required public init(decoder: PostboxDecoder) { + self.consumed = decoder.decodeInt32ForKey("c", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.consumed ? 1 : 0, forKey: "c") + } +} diff --git a/submodules/TelegramCore/TelegramCore/ConsumablePersonalMentionMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ConsumablePersonalMentionMessageAttribute.swift new file mode 100644 index 0000000000..4cb1268dc5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ConsumablePersonalMentionMessageAttribute.swift @@ -0,0 +1,26 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ConsumablePersonalMentionMessageAttribute: MessageAttribute { + public let consumed: Bool + public let pending: Bool + + public init(consumed: Bool, pending: Bool) { + self.consumed = consumed + self.pending = pending + } + + required public init(decoder: PostboxDecoder) { + self.consumed = decoder.decodeInt32ForKey("c", orElse: 0) != 0 + self.pending = decoder.decodeInt32ForKey("p", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.consumed ? 1 : 0, forKey: "c") + encoder.encodeInt32(self.pending ? 1 : 0, forKey: "p") + } +} diff --git a/submodules/TelegramCore/TelegramCore/ConsumePersonalMessageAction.swift b/submodules/TelegramCore/TelegramCore/ConsumePersonalMessageAction.swift new file mode 100644 index 0000000000..2cac19e09e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ConsumePersonalMessageAction.swift @@ -0,0 +1,27 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +final class ConsumePersonalMessageAction: PendingMessageActionData { + init() { + } + + init(decoder: PostboxDecoder) { + } + + func encode(_ encoder: PostboxEncoder) { + } + + func isEqual(to: PendingMessageActionData) -> Bool { + if let _ = to as? ConsumePersonalMessageAction { + return true + } else { + return false + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ContactManagement.swift b/submodules/TelegramCore/TelegramCore/ContactManagement.swift new file mode 100644 index 0000000000..a8c7b2d4bb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ContactManagement.swift @@ -0,0 +1,180 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif +import TelegramCorePrivateModule + +private func md5(_ data: Data) -> Data { + return data.withUnsafeBytes { bytes -> Data in + return CryptoMD5(bytes, Int32(data.count)) + } +} + +private func updatedRemoteContactPeers(network: Network, hash: Int32) -> Signal<([Peer], [PeerId: PeerPresence], Int32)?, NoError> { + return network.request(Api.functions.contacts.getContacts(hash: hash), automaticFloodWait: false) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> ([Peer], [PeerId: PeerPresence], Int32)? in + guard let result = result else { + return nil + } + switch result { + case .contactsNotModified: + return nil + case let .contacts(_, savedCount, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + return (peers, peerPresences, savedCount) + } + } +} + +private func hashForCountAndIds(count: Int32, ids: [Int32]) -> Int32 { + var acc: Int64 = 0 + + acc = (acc &* 20261) &+ Int64(count) + + for id in ids { + acc = (acc &* 20261) &+ Int64(id) + acc = acc & Int64(0x7FFFFFFF) + } + return Int32(acc & Int64(0x7FFFFFFF)) +} + +func syncContactsOnce(network: Network, postbox: Postbox, accountPeerId: PeerId) -> Signal { + let initialContactPeerIdsHash = postbox.transaction { transaction -> Int32 in + let contactPeerIds = transaction.getContactPeerIds() + let totalCount = transaction.getRemoteContactCount() + let peerIds = Set(contactPeerIds.filter({ $0.namespace == Namespaces.Peer.CloudUser })) + return hashForCountAndIds(count: totalCount, ids: peerIds.map({ $0.id }).sorted()) + } + + let updatedPeers = initialContactPeerIdsHash + |> mapToSignal { hash -> Signal<([Peer], [PeerId: PeerPresence], Int32)?, NoError> in + return updatedRemoteContactPeers(network: network, hash: hash) + } + + let appliedUpdatedPeers = updatedPeers + |> mapToSignal { peersAndPresences -> Signal in + if let (peers, peerPresences, totalCount) = peersAndPresences { + return postbox.transaction { transaction -> Signal in + let previousIds = transaction.getContactPeerIds() + let wasEmpty = previousIds.isEmpty + + transaction.replaceRemoteContactCount(totalCount) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + if wasEmpty { + var insertSignal: Signal = .complete() + for s in stride(from: 0, to: peers.count, by: 100) { + let partPeers = Array(peers[s ..< min(s + 100, peers.count)]) + let partSignal = postbox.transaction { transaction -> Void in + updatePeers(transaction: transaction, peers: partPeers, update: { return $1 }) + var updatedIds = transaction.getContactPeerIds() + updatedIds.formUnion(partPeers.map { $0.id }) + transaction.replaceContactPeerIds(updatedIds) + } + |> delay(0.1, queue: Queue.concurrentDefaultQueue()) + insertSignal = insertSignal |> then(partSignal) + } + + return insertSignal + } else { + transaction.replaceContactPeerIds(Set(peers.map { $0.id })) + return .complete() + } + } + |> switchToLatest + |> ignoreValues + } else { + return .complete() + } + } + + return appliedUpdatedPeers +} + +public func deleteContactPeerInteractively(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + return account.network.request(Api.functions.contacts.deleteContacts(id: [inputUser])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + } + return account.postbox.transaction { transaction -> Void in + var peerIds = transaction.getContactPeerIds() + if peerIds.contains(peerId) { + peerIds.remove(peerId) + transaction.replaceContactPeerIds(peerIds) + } + } + } + |> ignoreValues + } else { + return .complete() + } + } + |> switchToLatest +} + +public func deleteAllContacts(account: Account) -> Signal { + return account.postbox.transaction { transaction -> [Api.InputUser] in + return transaction.getContactPeerIds().compactMap(transaction.getPeer).compactMap({ apiInputUser($0) }).compactMap({ $0 }) + } + |> mapToSignal { users -> Signal in + let deleteContacts = account.network.request(Api.functions.contacts.deleteContacts(id: users)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + let deleteImported = account.network.request(Api.functions.contacts.resetSaved()) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + return combineLatest(deleteContacts, deleteImported) + |> mapToSignal { updates, _ -> Signal in + return account.postbox.transaction { transaction -> Void in + transaction.replaceContactPeerIds(Set()) + transaction.clearDeviceContactImportInfoIdentifiers() + } + |> mapToSignal { _ -> Signal in + account.restartContactManagement() + if let updates = updates { + account.stateManager.addUpdates(updates) + } + + return .complete() + } + |> ignoreValues + } + } +} + +public func resetSavedContacts(network: Network) -> Signal { + return network.request(Api.functions.contacts.resetSaved()) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ContactSyncManager.swift b/submodules/TelegramCore/TelegramCore/ContactSyncManager.swift new file mode 100644 index 0000000000..c6ccd94841 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ContactSyncManager.swift @@ -0,0 +1,425 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +private final class ContactSyncOperation { + let id: Int32 + var isRunning: Bool = false + let content: ContactSyncOperationContent + let disposable = DisposableSet() + + init(id: Int32, content: ContactSyncOperationContent) { + self.id = id + self.content = content + } +} + +private enum ContactSyncOperationContent { + case waitForUpdatedState + case updatePresences + case sync(importableContacts: [DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData]?) + case updateIsContact([(PeerId, Bool)]) +} + +private final class ContactSyncManagerImpl { + private let queue: Queue + private let postbox: Postbox + private let network: Network + private let accountPeerId: PeerId + private let stateManager: AccountStateManager + private var nextId: Int32 = 0 + private var operations: [ContactSyncOperation] = [] + + private var lastContactPresencesRequestTimestamp: Double? + private var reimportAttempts: [TelegramDeviceContactImportIdentifier: Double] = [:] + + private let importableContactsDisposable = MetaDisposable() + private let significantStateUpdateCompletedDisposable = MetaDisposable() + + init(queue: Queue, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) { + self.queue = queue + self.postbox = postbox + self.network = network + self.accountPeerId = accountPeerId + self.stateManager = stateManager + } + + deinit { + self.importableContactsDisposable.dispose() + } + + func beginSync(importableContacts: Signal<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], NoError>) { + self.importableContactsDisposable.set((importableContacts + |> deliverOn(self.queue)).start(next: { [weak self] importableContacts in + guard let strongSelf = self else { + return + } + strongSelf.addOperation(.waitForUpdatedState) + strongSelf.addOperation(.updatePresences) + strongSelf.addOperation(.sync(importableContacts: importableContacts)) + })) + self.significantStateUpdateCompletedDisposable.set((self.stateManager.significantStateUpdateCompleted + |> deliverOn(self.queue)).start(next: { [weak self] in + guard let strongSelf = self else { + return + } + let timestamp = CFAbsoluteTimeGetCurrent() + let shouldUpdate: Bool + if let lastContactPresencesRequestTimestamp = strongSelf.lastContactPresencesRequestTimestamp { + if timestamp > lastContactPresencesRequestTimestamp + 2.0 * 60.0 { + shouldUpdate = true + } else { + shouldUpdate = false + } + } else { + shouldUpdate = true + } + if shouldUpdate { + strongSelf.lastContactPresencesRequestTimestamp = timestamp + var found = false + for operation in strongSelf.operations { + if case .updatePresences = operation.content { + found = true + break + } + } + if !found { + strongSelf.addOperation(.updatePresences) + } + } + })) + } + + func addIsContactUpdates(_ updates: [(PeerId, Bool)]) { + self.addOperation(.updateIsContact(updates)) + } + + func addOperation(_ content: ContactSyncOperationContent) { + let id = self.nextId + self.nextId += 1 + let operation = ContactSyncOperation(id: id, content: content) + switch content { + case .waitForUpdatedState: + self.operations.append(operation) + case .updatePresences: + for i in (0 ..< self.operations.count).reversed() { + if case .updatePresences = self.operations[i].content { + if !self.operations[i].isRunning { + self.operations.remove(at: i) + } + } + } + self.operations.append(operation) + case .sync: + for i in (0 ..< self.operations.count).reversed() { + if case .sync = self.operations[i].content { + if !self.operations[i].isRunning { + self.operations.remove(at: i) + } + } + } + self.operations.append(operation) + case let .updateIsContact(updates): + var mergedUpdates: [(PeerId, Bool)] = [] + var removeIndices: [Int] = [] + for i in 0 ..< self.operations.count { + if case let .updateIsContact(operationUpdates) = self.operations[i].content { + if !self.operations[i].isRunning { + mergedUpdates.append(contentsOf: operationUpdates) + removeIndices.append(i) + } + } + } + mergedUpdates.append(contentsOf: updates) + for index in removeIndices.reversed() { + self.operations.remove(at: index) + } + if self.operations.isEmpty || !self.operations[0].isRunning { + self.operations.insert(operation, at: 0) + } else { + self.operations.insert(operation, at: 1) + } + } + self.updateOperations() + } + + func updateOperations() { + if let first = self.operations.first, !first.isRunning { + first.isRunning = true + let id = first.id + let queue = self.queue + self.startOperation(first.content, disposable: first.disposable, completion: { [weak self] in + queue.async { + guard let strongSelf = self else { + return + } + if let currentFirst = strongSelf.operations.first, currentFirst.id == id { + strongSelf.operations.remove(at: 0) + strongSelf.updateOperations() + } else { + assertionFailure() + } + } + }) + } + } + + func startOperation(_ operation: ContactSyncOperationContent, disposable: DisposableSet, completion: @escaping () -> Void) { + switch operation { + case .waitForUpdatedState: + disposable.add((self.stateManager.pollStateUpdateCompletion() + |> deliverOn(self.queue)).start(next: { _ in + completion() + })) + case .updatePresences: + disposable.add(updateContactPresences(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId).start(completed: { + completion() + })) + case let .sync(importableContacts): + let importSignal: Signal + if let importableContacts = importableContacts { + importSignal = pushDeviceContacts(postbox: self.postbox, network: self.network, importableContacts: importableContacts, reimportAttempts: self.reimportAttempts) + } else { + importSignal = .single(PushDeviceContactsResult(addedReimportAttempts: [:])) + } + disposable.add( + (syncContactsOnce(network: self.network, postbox: self.postbox, accountPeerId: self.accountPeerId) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(importSignal) + |> deliverOn(self.queue) + ).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } + for (identifier, timestamp) in result.addedReimportAttempts { + strongSelf.reimportAttempts[identifier] = timestamp + } + + completion() + })) + case let .updateIsContact(updates): + disposable.add((self.postbox.transaction { transaction -> Void in + var contactPeerIds = transaction.getContactPeerIds() + for (peerId, isContact) in updates { + if isContact { + contactPeerIds.insert(peerId) + } else { + contactPeerIds.remove(peerId) + } + } + transaction.replaceContactPeerIds(contactPeerIds) + } + |> deliverOnMainQueue).start(completed: { + completion() + })) + } + } +} + +private struct PushDeviceContactsResult { + let addedReimportAttempts: [TelegramDeviceContactImportIdentifier: Double] +} + +private func pushDeviceContacts(postbox: Postbox, network: Network, importableContacts: [DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], reimportAttempts: [TelegramDeviceContactImportIdentifier: Double]) -> Signal { + return postbox.transaction { transaction -> Signal in + var noLongerImportedIdentifiers = Set() + var updatedDataIdentifiers = Set() + var addedIdentifiers = Set() + var retryLaterIdentifiers = Set() + + addedIdentifiers.formUnion(importableContacts.keys.map(TelegramDeviceContactImportIdentifier.phoneNumber)) + transaction.enumerateDeviceContactImportInfoItems({ key, value in + if let identifier = TelegramDeviceContactImportIdentifier(key: key) { + addedIdentifiers.remove(identifier) + switch identifier { + case let .phoneNumber(number): + if let updatedData = importableContacts[number] { + if let value = value as? TelegramDeviceContactImportedData { + switch value { + case let .imported(imported): + if imported.data != updatedData { + updatedDataIdentifiers.insert(identifier) + } + case .retryLater: + retryLaterIdentifiers.insert(identifier) + } + } else { + assertionFailure() + } + } else { + noLongerImportedIdentifiers.insert(identifier) + } + } + } else { + assertionFailure() + } + return true + }) + + for identifier in noLongerImportedIdentifiers { + transaction.setDeviceContactImportInfo(identifier.key, value: nil) + } + + var orderedPushIdentifiers: [TelegramDeviceContactImportIdentifier] = [] + orderedPushIdentifiers.append(contentsOf: addedIdentifiers.sorted()) + orderedPushIdentifiers.append(contentsOf: updatedDataIdentifiers.sorted()) + orderedPushIdentifiers.append(contentsOf: retryLaterIdentifiers.sorted()) + + var currentContactDetails: [TelegramDeviceContactImportIdentifier: TelegramUser] = [:] + for peerId in transaction.getContactPeerIds() { + if let user = transaction.getPeer(peerId) as? TelegramUser, let phone = user.phone, !phone.isEmpty { + currentContactDetails[.phoneNumber(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone)))] = user + } + } + + let timestamp = CFAbsoluteTimeGetCurrent() + outer: for i in (0 ..< orderedPushIdentifiers.count).reversed() { + if let user = currentContactDetails[orderedPushIdentifiers[i]], case let .phoneNumber(number) = orderedPushIdentifiers[i], let data = importableContacts[number] { + if (user.firstName ?? "") == data.firstName && (user.lastName ?? "") == data.lastName { + transaction.setDeviceContactImportInfo(orderedPushIdentifiers[i].key, value: TelegramDeviceContactImportedData.imported(data: data, importedByCount: 0)) + orderedPushIdentifiers.remove(at: i) + continue outer + } + } + + if let attemptTimestamp = reimportAttempts[orderedPushIdentifiers[i]], attemptTimestamp + 60.0 * 60.0 * 24.0 > timestamp { + orderedPushIdentifiers.remove(at: i) + } + } + + var preparedContactData: [(DeviceContactNormalizedPhoneNumber, ImportableDeviceContactData)] = [] + for identifier in orderedPushIdentifiers { + if case let .phoneNumber(number) = identifier, let value = importableContacts[number] { + preparedContactData.append((number, value)) + } + } + + return pushDeviceContactData(postbox: postbox, network: network, contacts: preparedContactData) + } + |> switchToLatest +} + +private let importBatchCount: Int = 100 + +private func pushDeviceContactData(postbox: Postbox, network: Network, contacts: [(DeviceContactNormalizedPhoneNumber, ImportableDeviceContactData)]) -> Signal { + var batches: Signal = .single(PushDeviceContactsResult(addedReimportAttempts: [:])) + for s in stride(from: 0, to: contacts.count, by: importBatchCount) { + let batch = Array(contacts[s ..< min(s + importBatchCount, contacts.count)]) + batches = batches + |> mapToSignal { intermediateResult -> Signal in + return network.request(Api.functions.contacts.importContacts(contacts: zip(0 ..< batch.count, batch).map { index, item -> Api.InputContact in + return .inputPhoneContact(clientId: Int64(index), phone: item.0.rawValue, firstName: item.1.firstName, lastName: item.1.lastName) + })) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> PushDeviceContactsResult in + var addedReimportAttempts: [TelegramDeviceContactImportIdentifier: Double] = intermediateResult.addedReimportAttempts + if let result = result { + var addedContactPeerIds = Set() + var retryIndices = Set() + var importedCounts: [Int: Int32] = [:] + switch result { + case let .importedContacts(imported, popularInvites, retryContacts, users): + let peers = users.map { TelegramUser(user: $0) as Peer } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + for item in imported { + switch item { + case let .importedContact(userId, _): + addedContactPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + } + } + for item in retryContacts { + retryIndices.insert(Int(item)) + } + for item in popularInvites { + switch item { + case let .popularContact(clientId, importers): + importedCounts[Int(clientId)] = importers + } + } + } + let timestamp = CFAbsoluteTimeGetCurrent() + for i in 0 ..< batch.count { + let importedData: TelegramDeviceContactImportedData + if retryIndices.contains(i) { + importedData = .retryLater + addedReimportAttempts[.phoneNumber(batch[i].0)] = timestamp + } else { + importedData = .imported(data: batch[i].1, importedByCount: importedCounts[i] ?? 0) + } + transaction.setDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(batch[i].0).key, value: importedData) + } + var contactPeerIds = transaction.getContactPeerIds() + contactPeerIds.formUnion(addedContactPeerIds) + transaction.replaceContactPeerIds(contactPeerIds) + } else { + let timestamp = CFAbsoluteTimeGetCurrent() + for (number, _) in batch { + addedReimportAttempts[.phoneNumber(number)] = timestamp + transaction.setDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(number).key, value: TelegramDeviceContactImportedData.retryLater) + } + } + + return PushDeviceContactsResult(addedReimportAttempts: addedReimportAttempts) + } + } + } + } + return batches +} + +private func updateContactPresences(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal { + return network.request(Api.functions.contacts.getStatuses()) + |> `catch` { _ -> Signal<[Api.ContactStatus], NoError> in + return .single([]) + } + |> mapToSignal { statuses -> Signal in + return postbox.transaction { transaction -> Void in + var peerPresences: [PeerId: PeerPresence] = [:] + for status in statuses { + switch status { + case let .contactStatus(userId, status): + peerPresences[PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] = TelegramUserPresence(apiStatus: status) + } + } + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + } + |> ignoreValues + } +} + +final class ContactSyncManager { + private let queue = Queue() + private let impl: QueueLocalObject + + init(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) { + let queue = self.queue + self.impl = QueueLocalObject(queue: queue, generate: { + return ContactSyncManagerImpl(queue: queue, postbox: postbox, network: network, accountPeerId: accountPeerId, stateManager: stateManager) + }) + } + + func beginSync(importableContacts: Signal<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], NoError>) { + self.impl.with { impl in + impl.beginSync(importableContacts: importableContacts) + } + } + + func addIsContactUpdates(_ updates: [(PeerId, Bool)]) { + self.impl.with { impl in + impl.addIsContactUpdates(updates) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ContactsSettings.swift b/submodules/TelegramCore/TelegramCore/ContactsSettings.swift new file mode 100644 index 0000000000..794d7b394c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ContactsSettings.swift @@ -0,0 +1,34 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public struct ContactsSettings: Equatable, PreferencesEntry { + public var synchronizeContacts: Bool + + public static var defaultSettings: ContactsSettings { + return ContactsSettings(synchronizeContacts: true) + } + + public init(synchronizeContacts: Bool) { + self.synchronizeContacts = synchronizeContacts + } + + public init(decoder: PostboxDecoder) { + self.synchronizeContacts = decoder.decodeInt32ForKey("synchronizeContacts", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.synchronizeContacts ? 1 : 0, forKey: "synchronizeContacts") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? ContactsSettings { + return self == to + } else { + return false + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ContentPrivacySettings.swift b/submodules/TelegramCore/TelegramCore/ContentPrivacySettings.swift new file mode 100644 index 0000000000..1928ce35e3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ContentPrivacySettings.swift @@ -0,0 +1,70 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public final class ContentPrivacySettings: PreferencesEntry, Equatable { + public let enableSecretChatWebpagePreviews: Bool? + + public static var defaultSettings = ContentPrivacySettings(enableSecretChatWebpagePreviews: nil) + + public init(enableSecretChatWebpagePreviews: Bool?) { + self.enableSecretChatWebpagePreviews = enableSecretChatWebpagePreviews + } + + public init(decoder: PostboxDecoder) { + self.enableSecretChatWebpagePreviews = decoder.decodeOptionalInt32ForKey("enableSecretChatWebpagePreviews").flatMap { $0 != 0 } + } + + public func encode(_ encoder: PostboxEncoder) { + if let enableSecretChatWebpagePreviews = self.enableSecretChatWebpagePreviews { + encoder.encodeInt32(enableSecretChatWebpagePreviews ? 1 : 0, forKey: "enableSecretChatWebpagePreviews") + } else { + encoder.encodeNil(forKey: "enableSecretChatWebpagePreviews") + } + } + + public func withUpdatedEnableSecretChatWebpagePreviews(_ enableSecretChatWebpagePreviews: Bool) -> ContentPrivacySettings { + return ContentPrivacySettings(enableSecretChatWebpagePreviews: enableSecretChatWebpagePreviews) + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? ContentPrivacySettings else { + return false + } + + return self == to + } + + public static func ==(lhs: ContentPrivacySettings, rhs: ContentPrivacySettings) -> Bool { + if lhs.enableSecretChatWebpagePreviews != rhs.enableSecretChatWebpagePreviews { + return false + } + return true + } +} + +public func updateContentPrivacySettings(postbox: Postbox, _ f: @escaping (ContentPrivacySettings) -> ContentPrivacySettings) -> Signal { + return postbox.transaction { transaction -> Void in + var updated: ContentPrivacySettings? + transaction.updatePreferencesEntry(key: PreferencesKeys.contentPrivacySettings, { current in + if let current = current as? ContentPrivacySettings { + updated = f(current) + return updated + } else { + updated = f(ContentPrivacySettings.defaultSettings) + return updated + } + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ContentRequiresValidationMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ContentRequiresValidationMessageAttribute.swift new file mode 100644 index 0000000000..8fbcab08ec --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ContentRequiresValidationMessageAttribute.swift @@ -0,0 +1,17 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public class ContentRequiresValidationMessageAttribute: MessageAttribute { + public init() { + } + + required public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } +} diff --git a/submodules/TelegramCore/TelegramCore/ConvertGroupToSupergroup.swift b/submodules/TelegramCore/TelegramCore/ConvertGroupToSupergroup.swift new file mode 100644 index 0000000000..f94892bced --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ConvertGroupToSupergroup.swift @@ -0,0 +1,52 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ConvertGroupToSupergroupError { + case generic +} + +public func convertGroupToSupergroup(account: Account, peerId: PeerId) -> Signal { + return account.network.request(Api.functions.messages.migrateChat(chatId: peerId.id)) + |> mapError { _ -> ConvertGroupToSupergroupError in + return .generic + } + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + var createdPeerId: PeerId? + for message in updates.messages { + if apiMessagePeerId(message) != peerId { + createdPeerId = apiMessagePeerId(message) + break + } + } + + if let createdPeerId = createdPeerId { + return account.postbox.multiplePeersView([createdPeerId]) + |> filter { view in + return view.peers[createdPeerId] != nil + } + |> take(1) + |> map { _ in + return createdPeerId + } + |> mapError { _ -> ConvertGroupToSupergroupError in + return .generic + } + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) + } + return .fail(.generic) + } +} diff --git a/submodules/TelegramCore/TelegramCore/CoreSettings.swift b/submodules/TelegramCore/TelegramCore/CoreSettings.swift new file mode 100644 index 0000000000..87b262db74 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CoreSettings.swift @@ -0,0 +1,67 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public final class CoreSettings: PreferencesEntry, Equatable { + public let fastForward: Bool + + public static var defaultSettings = CoreSettings(fastForward: true) + + public init(fastForward: Bool) { + self.fastForward = fastForward + } + + public init(decoder: PostboxDecoder) { + self.fastForward = decoder.decodeInt32ForKey("fastForward", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.fastForward ? 1 : 0, forKey: "fastForward") + } + + public func withUpdatedFastForward(_ fastForward: Bool) -> CoreSettings { + return CoreSettings(fastForward: fastForward) + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? CoreSettings else { + return false + } + + return self == to + } + + public static func ==(lhs: CoreSettings, rhs: CoreSettings) -> Bool { + if lhs.fastForward != rhs.fastForward { + return false + } + return true + } +} + +public func updateCoreSettings(postbox: Postbox, _ f: @escaping (CoreSettings) -> CoreSettings) -> Signal { + return postbox.transaction { transaction -> Void in + var updated: CoreSettings? + transaction.updatePreferencesEntry(key: PreferencesKeys.coreSettings, { current in + if let current = current as? CoreSettings { + updated = f(current) + return updated + } else { + updated = f(CoreSettings.defaultSettings) + return updated + } + }) + } +} + diff --git a/submodules/TelegramCore/TelegramCore/CreateGroup.swift b/submodules/TelegramCore/TelegramCore/CreateGroup.swift new file mode 100644 index 0000000000..cf1fc64d9d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CreateGroup.swift @@ -0,0 +1,58 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum CreateGroupError { + case generic + case privacy + case restricted +} + +public func createGroup(account: Account, title: String, peerIds: [PeerId]) -> Signal { + return account.postbox.transaction { transaction -> Signal in + var inputUsers: [Api.InputUser] = [] + for peerId in peerIds { + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + inputUsers.append(inputUser) + } else { + return .single(nil) + } + } + return account.network.request(Api.functions.messages.createChat(users: inputUsers, title: title)) + |> mapError { error -> CreateGroupError in + if error.errorDescription == "USERS_TOO_FEW" { + return .privacy + } + return .generic + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + if let message = updates.messages.first, let peerId = apiMessagePeerId(message) { + return account.postbox.multiplePeersView([peerId]) + |> filter { view in + return view.peers[peerId] != nil + } + |> take(1) + |> introduceError(CreateGroupError.self) + |> map { _ in + return peerId + } + } else { + return .single(nil) + } + } + } + |> introduceError(CreateGroupError.self) + |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/CreateSecretChat.swift b/submodules/TelegramCore/TelegramCore/CreateSecretChat.swift new file mode 100644 index 0000000000..c3bcacb0a1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/CreateSecretChat.swift @@ -0,0 +1,57 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum CreateSecretChatError { + case generic +} + +public func createSecretChat(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + return validatedEncryptionConfig(postbox: account.postbox, network: account.network) + |> mapError { _ -> CreateSecretChatError in return .generic } + |> mapToSignal { config -> Signal in + let aBytes = malloc(256)! + let _ = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self)) + let a = MemoryBuffer(memory: aBytes, capacity: 256, length: 256, freeWhenDone: true) + + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let aData = a.makeData() + let ga = MTExp(g, aData, p)! + + if !MTCheckIsSafeGAOrB(ga, p) { + return .fail(.generic) + } + + return account.network.request(Api.functions.messages.requestEncryption(userId: inputUser, randomId: Int32(bitPattern: arc4random()), gA: Buffer(data: ga))) + |> mapError { _ -> CreateSecretChatError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> PeerId in + updateSecretChat(accountPeerId: account.peerId, transaction: transaction, chat: result, requestData: SecretChatRequestData(g: config.g, p: config.p, a: a)) + + return result.peerId + } |> mapError { _ -> CreateSecretChatError in return .generic } + } + } + } else { + return .fail(.generic) + } + } |> mapError { _ -> CreateSecretChatError in return .generic } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/Crypto.h b/submodules/TelegramCore/TelegramCore/Crypto.h new file mode 100644 index 0000000000..d50d4f1e40 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Crypto.h @@ -0,0 +1,22 @@ +#ifndef __CRYPTO_H_ +#define __CRYPTO_H_ + +#import + +NSData * _Nonnull CryptoMD5(const void *bytes, int count); +NSData * _Nonnull CryptoSHA1(const void *bytes, int count); +NSData * _Nonnull CryptoSHA256(const void *bytes, int count); +NSData * _Nonnull CryptoSHA512(const void *bytes, int count); + +@interface IncrementalMD5 : NSObject + +- (instancetype _Nonnull)init; +- (void)update:(NSData * _Nonnull)data; +- (void)update:(const void * _Nonnull)bytes count:(int)count; +- (NSData * _Nonnull)complete; + +@end + +NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data); + +#endif diff --git a/submodules/TelegramCore/TelegramCore/Crypto.m b/submodules/TelegramCore/TelegramCore/Crypto.m new file mode 100644 index 0000000000..1f8529251c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Crypto.m @@ -0,0 +1,78 @@ +#include "Crypto.h" + +#import + +NSData * _Nonnull CryptoMD5(const void *bytes, int count) { + NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH]; + CC_MD5(bytes, (CC_LONG)count, result.mutableBytes); + return result; +} + +NSData * _Nonnull CryptoSHA1(const void *bytes, int count) { + NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(bytes, (CC_LONG)count, result.mutableBytes); + return result; +} + +NSData * _Nonnull CryptoSHA256(const void *bytes, int count) { + NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(bytes, (CC_LONG)count, result.mutableBytes); + return result; +} + +NSData * _Nonnull CryptoSHA512(const void *bytes, int count) { + NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA512_DIGEST_LENGTH]; + CC_SHA512(bytes, (CC_LONG)count, result.mutableBytes); + return result; +} + +@interface IncrementalMD5 () { + CC_MD5_CTX _ctx; +} + +@end + +@implementation IncrementalMD5 + +- (instancetype _Nonnull)init { + self = [super init]; + if (self != nil) { + CC_MD5_Init(&_ctx); + } + return self; +} + +- (void)update:(NSData * _Nonnull)data { + CC_MD5_Update(&_ctx, data.bytes, (CC_LONG)data.length); +} + +- (void)update:(const void *)bytes count:(int)count { + CC_MD5_Update(&_ctx, bytes, (CC_LONG)count); +} + +- (NSData *)complete { + NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH]; + CC_MD5_Final(result.mutableBytes, &_ctx); + return result; +} + +@end + +NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data) { + if (key.length != 32) { + return nil; + } + if (iv.length != 16) { + return nil; + } + NSMutableData *processedData = [[NSMutableData alloc] initWithLength:data.length]; + size_t processedCount = 0; + CCStatus status = CCCrypt(encrypt ? kCCEncrypt : kCCDecrypt, kCCAlgorithmAES128, 0, key.bytes, key.length, iv.bytes, data.bytes, data.length, processedData.mutableBytes, processedData.length, &processedCount); + if (status != kCCSuccess) { + return nil; + } + if (processedCount != (size_t)processedData.length) { + return nil; + } + return processedData; +} diff --git a/submodules/TelegramCore/TelegramCore/DecryptedResourceData.swift b/submodules/TelegramCore/TelegramCore/DecryptedResourceData.swift new file mode 100644 index 0000000000..238bfe8b80 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DecryptedResourceData.swift @@ -0,0 +1,20 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public func decryptedResourceData(data: MediaResourceData, resource: MediaResource, params: Any) -> Data? { + guard data.complete else { + return nil + } + guard let data = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.mappedRead]) else { + return nil + } + if let resource = resource as? EncryptedMediaResource { + return resource.decrypt(data: data, params: params) + } else { + return data + } +} diff --git a/submodules/TelegramCore/TelegramCore/DeepLinkInfo.swift b/submodules/TelegramCore/TelegramCore/DeepLinkInfo.swift new file mode 100644 index 0000000000..c473c19ffd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DeepLinkInfo.swift @@ -0,0 +1,24 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +#else +import SwiftSignalKit +#endif + +public struct DeepLinkInfo { + public let message: String + public let entities: [MessageTextEntity] + public let updateApp: Bool +} + +public func getDeepLinkInfo(network: Network, path: String) -> Signal { + return network.request(Api.functions.help.getDeepLinkInfo(path: path)) |> retryRequest + |> map { value -> DeepLinkInfo? in + switch value { + case .deepLinkInfoEmpty: + return nil + case let .deepLinkInfo(flags, message, entities): + return DeepLinkInfo(message: message, entities: entities != nil ? messageTextEntitiesFromApiEntities(entities!) : [], updateApp: (flags & (1 << 0)) != 0) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/DeleteMessages.swift b/submodules/TelegramCore/TelegramCore/DeleteMessages.swift new file mode 100644 index 0000000000..07fcdbdd46 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DeleteMessages.swift @@ -0,0 +1,40 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +private func removeMessageMedia(message: Message, mediaBox: MediaBox) { + for media in message.media { + if let image = media as? TelegramMediaImage { + let _ = mediaBox.removeCachedResources(Set(image.representations.map({ WrappedMediaResourceId($0.resource.id) }))).start() + } else if let file = media as? TelegramMediaFile { + let _ = mediaBox.removeCachedResources(Set(file.previewRepresentations.map({ WrappedMediaResourceId($0.resource.id) }))).start() + let _ = mediaBox.removeCachedResources(Set([WrappedMediaResourceId(file.resource.id)])).start() + } + } +} + +public func deleteMessages(transaction: Transaction, mediaBox: MediaBox, ids: [MessageId]) { + for id in ids { + if id.peerId.namespace == Namespaces.Peer.SecretChat { + if let message = transaction.getMessage(id) { + removeMessageMedia(message: message, mediaBox: mediaBox) + } + } + } + transaction.deleteMessages(ids) +} + +public func clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId) { + if peerId.namespace == Namespaces.Peer.SecretChat { + transaction.withAllMessages(peerId: peerId, { message in + removeMessageMedia(message: message, mediaBox: mediaBox) + return true + }) + } + transaction.clearHistory(peerId) +} diff --git a/submodules/TelegramCore/TelegramCore/DeleteMessagesInteractively.swift b/submodules/TelegramCore/TelegramCore/DeleteMessagesInteractively.swift new file mode 100644 index 0000000000..10214a7dfa --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DeleteMessagesInteractively.swift @@ -0,0 +1,151 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum InteractiveMessagesDeletionType: Int32 { + case forLocalPeer = 0 + case forEveryone = 1 +} + +public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId], type: InteractiveMessagesDeletionType) -> Signal { + return postbox.transaction { transaction -> Void in + var messageIdsByPeerId: [PeerId: [MessageId]] = [:] + for id in messageIds { + if messageIdsByPeerId[id.peerId] == nil { + messageIdsByPeerId[id.peerId] = [id] + } else { + messageIdsByPeerId[id.peerId]!.append(id) + } + } + for (peerId, peerMessageIds) in messageIdsByPeerId { + if peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudUser { + cloudChatAddRemoveMessagesOperation(transaction: transaction, peerId: peerId, messageIds: peerMessageIds, type: CloudChatRemoveMessagesType(type)) + } else if peerId.namespace == Namespaces.Peer.SecretChat { + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var layer: SecretChatLayer? + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + if let layer = layer { + var globallyUniqueIds: [Int64] = [] + for messageId in peerMessageIds { + if let message = transaction.getMessage(messageId), let globallyUniqueId = message.globallyUniqueId { + globallyUniqueIds.append(globallyUniqueId) + } + } + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.deleteMessages(layer: layer, actionGloballyUniqueId: arc4random64(), globallyUniqueIds: globallyUniqueIds), state: state) + if updatedState != state { + transaction.setPeerChatState(peerId, state: updatedState) + } + } + } + } + } + deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: messageIds) + } +} + +public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveMessagesDeletionType) -> Signal { + return postbox.transaction { transaction -> Void in + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel { + cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: type) + var topIndex: MessageIndex? + if let topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud), let topMessage = transaction.getMessage(topMessageId) { + topIndex = topMessage.index + } + clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) + if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference { + cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), type: type) + clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId) + } + if let topIndex = topIndex { + if peerId.namespace == Namespaces.Peer.CloudUser { + let _ = transaction.addMessages([StoreMessage(id: topIndex.id, globallyUniqueId: nil, groupingKey: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random) + } else { + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topIndex.timestamp, forceRootGroupIfNotExists: false) + } + } + } else if peerId.namespace == Namespaces.Peer.SecretChat { + clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) + + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var layer: SecretChatLayer? + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + + if let layer = layer { + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.clearHistory(layer: layer, actionGloballyUniqueId: arc4random64()), state: state) + if updatedState != state { + transaction.setPeerChatState(peerId, state: updatedState) + } + } + } + } + } +} + +public func clearAuthorHistory(account: Account, peerId: PeerId, memberId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputChannel = apiInputChannel(peer), let inputUser = apiInputUser(memberPeer) { + + let signal = account.network.request(Api.functions.channels.deleteUserHistory(channel: inputChannel, userId: inputUser)) + |> map { result -> Api.messages.AffectedHistory? in + return result + } + |> `catch` { _ -> Signal in + return .fail(false) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedHistory(pts, ptsCount, offset): + account.stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + if offset == 0 { + return .fail(true) + } else { + return .complete() + } + } + } else { + return .fail(true) + } + } + return (signal + |> restart) + |> `catch` { success -> Signal in + if success { + return account.postbox.transaction { transaction -> Void in + transaction.removeAllMessagesWithAuthor(peerId, authorId: memberId, namespace: Namespaces.Message.Cloud) + } + } else { + return .complete() + } + } + } else { + return .complete() + } + } |> switchToLatest +} + diff --git a/submodules/TelegramCore/TelegramCore/DeserializeFunctionResponse.swift b/submodules/TelegramCore/TelegramCore/DeserializeFunctionResponse.swift new file mode 100644 index 0000000000..deec67021c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DeserializeFunctionResponse.swift @@ -0,0 +1,27 @@ +import Foundation + +public final class FunctionDescription { + let name: String + let parameters: [(String, Any)] + + init(name: String, parameters: [(String, Any)]) { + self.name = name + self.parameters = parameters + } +} + +public final class DeserializeFunctionResponse { + private let f: (Buffer) -> T? + + public init(_ f: @escaping (Buffer) -> T?) { + self.f = f + } + + public func parse(_ buffer: Buffer) -> T? { + return self.f(buffer) + } +} + +protocol TypeConstructorDescription { + func descriptionFields() -> (String, [(String, Any)]) +} diff --git a/submodules/TelegramCore/TelegramCore/DeviceContact.swift b/submodules/TelegramCore/TelegramCore/DeviceContact.swift new file mode 100644 index 0000000000..f8ac991254 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/DeviceContact.swift @@ -0,0 +1,108 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public struct DeviceContactNormalizedPhoneNumber: Hashable, RawRepresentable { + public let rawValue: String + + public init(rawValue: String) { + self.rawValue = rawValue + } +} + +public final class DeviceContactPhoneNumberValue: Equatable { + public let plain: String + public let normalized: DeviceContactNormalizedPhoneNumber + + public init(plain: String, normalized: DeviceContactNormalizedPhoneNumber) { + self.plain = plain + self.normalized = normalized + } + + public static func ==(lhs: DeviceContactPhoneNumberValue, rhs: DeviceContactPhoneNumberValue) -> Bool { + if lhs.plain != rhs.plain { + return false + } + if lhs.normalized != rhs.normalized { + return false + } + return true + } +} + +public final class DeviceContactPhoneNumber: Equatable { + public let label: String + public let number: DeviceContactPhoneNumberValue + + public init(label: String, number: DeviceContactPhoneNumberValue) { + self.label = label + self.number = number + } + + public static func ==(lhs: DeviceContactPhoneNumber, rhs: DeviceContactPhoneNumber) -> Bool { + return lhs.label == rhs.label && lhs.number == rhs.number + } +} + +public final class DeviceContact: Equatable { + public let id: String + public let firstName: String + public let lastName: String + public let phoneNumbers: [DeviceContactPhoneNumber] + + public init(id: String, firstName: String, lastName: String, phoneNumbers: [DeviceContactPhoneNumber]) { + self.id = id + self.firstName = firstName + self.lastName = lastName + self.phoneNumbers = phoneNumbers + } + + public static func ==(lhs: DeviceContact, rhs: DeviceContact) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.firstName != rhs.firstName { + return false + } + if lhs.lastName != rhs.lastName { + return false + } + if lhs.phoneNumbers != rhs.phoneNumbers { + return false + } + return true + } +} + +public final class ImportableDeviceContactData: Equatable, PostboxCoding { + public let firstName: String + public let lastName: String + + public init(firstName: String, lastName: String) { + self.firstName = firstName + self.lastName = lastName + } + + public init(decoder: PostboxDecoder) { + self.firstName = decoder.decodeStringForKey("f", orElse: "") + self.lastName = decoder.decodeStringForKey("l", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.firstName, forKey: "f") + encoder.encodeString(self.lastName, forKey: "l") + } + + public static func ==(lhs: ImportableDeviceContactData, rhs: ImportableDeviceContactData) -> Bool { + if lhs.firstName != rhs.firstName { + return false + } + if lhs.lastName != rhs.lastName { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/Download.swift b/submodules/TelegramCore/TelegramCore/Download.swift new file mode 100644 index 0000000000..6d20992cc6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Download.swift @@ -0,0 +1,307 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +private func roundUp(_ value: Int, to multiple: Int) -> Int { + if multiple == 0 { + return value + } + + let remainder = value % multiple + if remainder == 0 { + return value + } + + return value + multiple - remainder +} + +enum UploadPartError { + case generic + case invalidMedia +} + + +class Download: NSObject, MTRequestMessageServiceDelegate { + let datacenterId: Int + let isCdn: Bool + let context: MTContext + let mtProto: MTProto + let requestService: MTRequestMessageService + + private var shouldKeepConnectionDisposable: Disposable? + + init(queue: Queue, datacenterId: Int, isMedia: Bool, isCdn: Bool, context: MTContext, masterDatacenterId: Int, usageInfo: MTNetworkUsageCalculationInfo?, shouldKeepConnection: Signal) { + self.datacenterId = datacenterId + self.isCdn = isCdn + self.context = context + + self.mtProto = MTProto(context: self.context, datacenterId: datacenterId, usageCalculationInfo: usageInfo) + self.mtProto.cdn = isCdn + self.mtProto.useTempAuthKeys = self.context.useTempAuthKeys && !isCdn + self.mtProto.media = isMedia + if !isCdn && datacenterId != masterDatacenterId { + self.mtProto.authTokenMasterDatacenterId = masterDatacenterId + self.mtProto.requiredAuthToken = Int(datacenterId) as NSNumber + } + self.requestService = MTRequestMessageService(context: self.context) + self.requestService.forceBackgroundRequests = true + + super.init() + + self.requestService.delegate = self + self.mtProto.add(self.requestService) + + let mtProto = self.mtProto + self.shouldKeepConnectionDisposable = (shouldKeepConnection |> distinctUntilChanged |> deliverOn(queue)).start(next: { [weak mtProto] value in + if let mtProto = mtProto { + if value { + Logger.shared.log("Network", "Resume worker network connection") + mtProto.resume() + } else { + Logger.shared.log("Network", "Pause worker network connection") + mtProto.pause() + } + } + }) + } + + deinit { + self.mtProto.remove(self.requestService) + self.mtProto.stop() + self.mtProto.finalizeSession() + self.shouldKeepConnectionDisposable?.dispose() + } + + func requestMessageServiceAuthorizationRequired(_ requestMessageService: MTRequestMessageService!) { + self.context.updateAuthTokenForDatacenter(withId: self.datacenterId, authToken: nil) + self.context.authTokenForDatacenter(withIdRequired: self.datacenterId, authToken:self.mtProto.requiredAuthToken, masterDatacenterId: self.mtProto.authTokenMasterDatacenterId) + } + + func uploadPart(fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal { + return Signal { subscriber in + let request = MTRequest() + + let saveFilePart: (FunctionDescription, Buffer, DeserializeFunctionResponse) + if asBigPart { + let totalParts: Int32 + if let bigTotalParts = bigTotalParts { + totalParts = Int32(bigTotalParts) + } else { + totalParts = -1 + } + saveFilePart = Api.functions.upload.saveBigFilePart(fileId: fileId, filePart: Int32(index), fileTotalParts: totalParts, bytes: Buffer(data: data)) + } else { + saveFilePart = Api.functions.upload.saveFilePart(fileId: fileId, filePart: Int32(index), bytes: Buffer(data: data)) + } + + request.setPayload(saveFilePart.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(saveFilePart.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(saveFilePart.0)), responseParser: { response in + if let result = saveFilePart.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + subscriber.putCompletion() + } + } + + let internalId: Any! = request.internalId + + self.requestService.add(request) + + return ActionDisposable { + self.requestService.removeRequest(byInternalId: internalId) + } + } |> `catch` { value -> Signal in + if value.errorCode == 400 { + return .fail(.invalidMedia) + } else { + return .fail(.generic) + } + } + } + + func webFilePart(location: Api.InputWebFileLocation, offset: Int, length: Int) -> Signal { + return Signal { subscriber in + let request = MTRequest() + + var updatedLength = roundUp(length, to: 4096) + while updatedLength % 4096 != 0 || 1048576 % updatedLength != 0 { + updatedLength += 1 + } + + let data = Api.functions.upload.getWebFile(location: location, offset: Int32(offset), limit: Int32(updatedLength)) + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedFunctionDescription(data.0)), responseParser: { response in + if let result = data.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + if let result = (boxedResponse as! BoxedMessage).body as? Api.upload.WebFile { + switch result { + case .webFile(_, _, _, _, let bytes): + subscriber.putNext(bytes.makeData()) + } + subscriber.putCompletion() + } + else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + } + } + + let internalId: Any! = request.internalId + + self.requestService.add(request) + + return ActionDisposable { + self.requestService.removeRequest(byInternalId: internalId) + } + } |> retryRequest + } + + func part(location: Api.InputFileLocation, offset: Int, length: Int) -> Signal { + return Signal { subscriber in + let request = MTRequest() + + var updatedLength = roundUp(length, to: 4096) + while updatedLength % 4096 != 0 || 1048576 % updatedLength != 0 { + updatedLength += 1 + } + + let data = Api.functions.upload.getFile(location: location, offset: Int32(offset), limit: Int32(updatedLength)) + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in + if let result = data.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + if let result = (boxedResponse as! BoxedMessage).body as? Api.upload.File { + switch result { + case let .file(_, _, bytes): + subscriber.putNext(bytes.makeData()) + case .fileCdnRedirect: + break + } + subscriber.putCompletion() + } + else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + } + } + + let internalId: Any! = request.internalId + + self.requestService.add(request) + + return ActionDisposable { + self.requestService.removeRequest(byInternalId: internalId) + } + } + |> retryRequest + } + + func request(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse)) -> Signal { + return Signal { subscriber in + let request = MTRequest() + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in + if let result = data.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + if let result = (boxedResponse as! BoxedMessage).body as? T { + subscriber.putNext(result) + subscriber.putCompletion() + } + else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + } + } + + let internalId: Any! = request.internalId + + self.requestService.add(request) + + return ActionDisposable { + self.requestService.removeRequest(byInternalId: internalId) + } + } + } + + func rawRequest(_ data: (FunctionDescription, Buffer, (Buffer) -> Any?)) -> Signal { + let requestService = self.requestService + return Signal { subscriber in + let request = MTRequest() + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in + if let result = data.2(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + subscriber.putNext((boxedResponse as! BoxedMessage).body) + subscriber.putCompletion() + } + } + + let internalId: Any! = request.internalId + + requestService.add(request) + + return ActionDisposable { [weak requestService] in + requestService?.removeRequest(byInternalId: internalId) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/EarliestUnseenPersonalMentionMessage.swift b/submodules/TelegramCore/TelegramCore/EarliestUnseenPersonalMentionMessage.swift new file mode 100644 index 0000000000..adfeb61e91 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/EarliestUnseenPersonalMentionMessage.swift @@ -0,0 +1,71 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum EarliestUnseenPersonalMentionMessageResult: Equatable { + case loading + case result(MessageId?) +} + +public func earliestUnseenPersonalMentionMessage(account: Account, peerId: PeerId) -> Signal { + return account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .lowerBound, anchorIndex: .lowerBound, count: 4, fixedCombinedReadStates: nil, tagMask: .unseenPersonalMessage, additionalData: [.peerChatState(peerId)]) + |> mapToSignal { view -> Signal in + if view.0.isLoading { + return .single(.loading) + } + if let message = view.0.entries.first?.message { + if peerId.namespace == Namespaces.Peer.CloudChannel { + var invalidatedPts: Int32? + for data in view.0.additionalData { + switch data { + case let .peerChatState(_, state): + if let state = state as? ChannelState { + invalidatedPts = state.invalidatedPts + } + default: + break + } + } + if let invalidatedPts = invalidatedPts { + var messagePts: Int32? + for attribute in message.attributes { + if let attribute = attribute as? ChannelMessageStateVersionAttribute { + messagePts = attribute.pts + break + } + } + + if let messagePts = messagePts { + if messagePts < invalidatedPts { + return .single(.loading) + } + } + } + return .single(.result(message.id)) + } else { + return .single(.result(message.id)) + } + } else { + return .single(.result(nil)) + } + } + |> distinctUntilChanged + |> take(until: { value in + if case .result = value { + return SignalTakeAction(passthrough: true, complete: true) + } else { + return SignalTakeAction(passthrough: true, complete: false) + } + }) +} diff --git a/submodules/TelegramCore/TelegramCore/EditedMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/EditedMessageAttribute.swift new file mode 100644 index 0000000000..a1b9e4f541 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/EditedMessageAttribute.swift @@ -0,0 +1,22 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class EditedMessageAttribute: MessageAttribute { + public let date: Int32 + + init(date: Int32) { + self.date = date + } + + required public init(decoder: PostboxDecoder) { + self.date = decoder.decodeInt32ForKey("d", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.date, forKey: "d") + } +} diff --git a/submodules/TelegramCore/TelegramCore/Either.swift b/submodules/TelegramCore/TelegramCore/Either.swift new file mode 100644 index 0000000000..1478adbc58 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Either.swift @@ -0,0 +1,6 @@ +import Foundation + +public enum Either { + case left(value: Left) + case right(value: Right) +} diff --git a/submodules/TelegramCore/TelegramCore/EmojiKeywords.swift b/submodules/TelegramCore/TelegramCore/EmojiKeywords.swift new file mode 100644 index 0000000000..e08a1d1300 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/EmojiKeywords.swift @@ -0,0 +1,188 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +func emojiKeywordColletionIdForCode(_ code: String) -> ItemCollectionId { + return ItemCollectionId(namespace: Namespaces.ItemCollection.EmojiKeywords, id: Int64(HashFunctions.murMurHash32(code))) +} + +public final class EmojiKeywordCollectionInfo: ItemCollectionInfo, Equatable { + public let id: ItemCollectionId + public let languageCode: String + public let inputLanguageCode: String + public let version: Int32 + public let timestamp: Int32 + + public init(languageCode: String, inputLanguageCode: String, version: Int32, timestamp: Int32) { + self.id = emojiKeywordColletionIdForCode(inputLanguageCode) + self.languageCode = languageCode + self.inputLanguageCode = inputLanguageCode + self.version = version + self.timestamp = timestamp + } + + public init(decoder: PostboxDecoder) { + self.id = ItemCollectionId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) + self.languageCode = decoder.decodeStringForKey("lc", orElse: "") + self.inputLanguageCode = decoder.decodeStringForKey("ilc", orElse: "") + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.id.namespace, forKey: "i.n") + encoder.encodeInt64(self.id.id, forKey: "i.i") + encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeString(self.inputLanguageCode, forKey: "ilc") + encoder.encodeInt32(self.version, forKey: "v") + encoder.encodeInt32(self.timestamp, forKey: "t") + } + + public static func ==(lhs: EmojiKeywordCollectionInfo, rhs: EmojiKeywordCollectionInfo) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.languageCode != rhs.languageCode { + return false + } + if lhs.inputLanguageCode != rhs.inputLanguageCode { + return false + } + if lhs.version != rhs.version { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + return true + } +} + +public final class EmojiKeywordItem: ItemCollectionItem, Equatable { + public let index: ItemCollectionItemIndex + public let collectionId: ItemCollectionId.Id + public let keyword: String + public let emoticons: [String] + public let indexKeys: [MemoryBuffer] + + public init(index: ItemCollectionItemIndex, collectionId: ItemCollectionId.Id, keyword: String, emoticons: [String], indexKeys: [MemoryBuffer]) { + self.index = index + self.collectionId = collectionId + self.keyword = keyword + self.emoticons = emoticons + self.indexKeys = indexKeys + } + + public init(decoder: PostboxDecoder) { + self.index = ItemCollectionItemIndex(index: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) + self.collectionId = decoder.decodeInt64ForKey("c", orElse: 0) + self.keyword = decoder.decodeStringForKey("k", orElse: "") + self.emoticons = decoder.decodeStringArrayForKey("e") + self.indexKeys = decoder.decodeBytesArrayForKey("s") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.index.index, forKey: "i.n") + encoder.encodeInt64(self.index.id, forKey: "i.i") + encoder.encodeInt64(self.collectionId, forKey: "c") + encoder.encodeString(self.keyword, forKey: "k") + encoder.encodeStringArray(self.emoticons, forKey: "e") + encoder.encodeBytesArray(self.indexKeys, forKey: "s") + } + + public static func ==(lhs: EmojiKeywordItem, rhs: EmojiKeywordItem) -> Bool { + return lhs.index == rhs.index && lhs.collectionId == rhs.collectionId && lhs.keyword == rhs.keyword && lhs.emoticons == rhs.emoticons && lhs.indexKeys == rhs.indexKeys + } +} + +private let refreshTimeout: Int32 = 60 * 60 + +private enum SearchEmojiKeywordsIntermediateResult { + case updating(timestamp: Int32?) + case completed([EmojiKeywordItem]) +} + +public func searchEmojiKeywords(postbox: Postbox, inputLanguageCode: String, query: String, completeMatch: Bool) -> Signal<[EmojiKeywordItem], NoError> { + guard !query.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { + return .single([]) + } + let collectionId = emojiKeywordColletionIdForCode(inputLanguageCode) + + let search: (Transaction) -> [EmojiKeywordItem] = { transaction in + let queryTokens = stringIndexTokens(query, transliteration: .none) + if let firstQueryToken = queryTokens.first { + let query: ItemCollectionSearchQuery = completeMatch ? .exact(firstQueryToken) : .matching(queryTokens) + let items = transaction.searchItemCollection(namespace: Namespaces.ItemCollection.EmojiKeywords, query: query).filter { item -> Bool in + if let item = item as? EmojiKeywordItem, item.collectionId == collectionId.id { + return true + } else { + return false + } + } as? [EmojiKeywordItem] + + if let items = items { + return items.sorted(by: { lhs, rhs -> Bool in + if lhs.keyword.count == rhs.keyword.count { + return lhs.keyword < rhs.keyword + } else { + return lhs.keyword.count < rhs.keyword.count + } + }) + } + } + return [] + } + + return postbox.transaction { transaction -> Signal in + let currentTime = Int32(CFAbsoluteTimeGetCurrent()) + let info = transaction.getItemCollectionInfo(collectionId: collectionId) + if let info = info as? EmojiKeywordCollectionInfo { + if info.timestamp + refreshTimeout < currentTime { + addSynchronizeEmojiKeywordsOperation(transaction: transaction, inputLanguageCode: inputLanguageCode, languageCode: info.languageCode, fromVersion: info.version) + return .single(.updating(timestamp: info.timestamp)) + } else { + return .single(.completed(search(transaction))) + } + } else { + addSynchronizeEmojiKeywordsOperation(transaction: transaction, inputLanguageCode: inputLanguageCode, languageCode: nil, fromVersion: nil) + return .single(.updating(timestamp: nil)) + } + } + |> switchToLatest + |> mapToSignal { intermediateResult -> Signal<[EmojiKeywordItem], NoError> in + switch intermediateResult { + case let .updating(timestamp): + return postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.EmojiKeywords], aroundIndex: nil, count: 10) + |> filter { view -> Bool in + for info in view.collectionInfos { + if let info = info.1 as? EmojiKeywordCollectionInfo, info.id == collectionId { + if let timestamp = timestamp { + return timestamp < info.timestamp + } else { + return true + } + } + } + return false + } + |> take(1) + |> mapToSignal { view -> Signal<[EmojiKeywordItem], NoError> in + for info in view.collectionInfos { + if let info = info.1 as? EmojiKeywordCollectionInfo, info.id == collectionId { + return postbox.transaction { transaction -> [EmojiKeywordItem] in + return search(transaction) + } + } + } + return .complete() + } + case let .completed(items): + return .single(items) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/EncryptedMediaResource.swift b/submodules/TelegramCore/TelegramCore/EncryptedMediaResource.swift new file mode 100644 index 0000000000..034e5a1511 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/EncryptedMediaResource.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol EncryptedMediaResource { + func decrypt(data: Data, params: Any) -> Data? +} diff --git a/submodules/TelegramCore/TelegramCore/EnqueueMessage.swift b/submodules/TelegramCore/TelegramCore/EnqueueMessage.swift new file mode 100644 index 0000000000..23619413e2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/EnqueueMessage.swift @@ -0,0 +1,555 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum EnqueueMessageGrouping { + case none + case auto +} + +public enum EnqueueMessage { + case message(text: String, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, replyToMessageId: MessageId?, localGroupingKey: Int64?) + case forward(source: MessageId, grouping: EnqueueMessageGrouping) + + public func withUpdatedReplyToMessageId(_ replyToMessageId: MessageId?) -> EnqueueMessage { + switch self { + case let .message(text, attributes, mediaReference, _, localGroupingKey): + return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey) + case .forward: + return self + } + } + + public func withUpdatedAttributes(_ f: ([MessageAttribute]) -> [MessageAttribute]) -> EnqueueMessage { + switch self { + case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): + return .message(text: text, attributes: f(attributes), mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey) + case .forward: + return self + } + } +} + +func augmentMediaWithReference(_ mediaReference: AnyMediaReference) -> Media { + if let file = mediaReference.media as? TelegramMediaFile { + if file.partialReference != nil { + return file + } else { + return file.withUpdatedPartialReference(mediaReference.partial) + } + } else if let image = mediaReference.media as? TelegramMediaImage { + if image.partialReference != nil { + return image + } else { + return image.withUpdatedPartialReference(mediaReference.partial) + } + } else { + return mediaReference.media + } +} + +private func convertForwardedMediaForSecretChat(_ media: Media) -> Media { + if let file = media as? TelegramMediaFile { + return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: file.partialReference, resource: file.resource, previewRepresentations: file.previewRepresentations, immediateThumbnailData: file.immediateThumbnailData, mimeType: file.mimeType, size: file.size, attributes: file.attributes) + } else if let image = media as? TelegramMediaImage { + return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: image.reference, partialReference: image.partialReference) + } else { + return media + } +} + +private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAttribute]) -> [MessageAttribute] { + return attributes.filter { attribute in + switch attribute { + case _ as TextEntitiesMessageAttribute: + return true + case _ as InlineBotMessageAttribute: + return true + case _ as OutgoingMessageInfoAttribute: + return true + case _ as OutgoingContentInfoMessageAttribute: + return true + case _ as ReplyMarkupMessageAttribute: + return true + case _ as OutgoingChatContextResultMessageAttribute: + return true + case _ as AutoremoveTimeoutMessageAttribute: + return true + case _ as NotificationInfoMessageAttribute: + return true + default: + return false + } + } +} + +private func filterMessageAttributesForForwardedMessage(_ attributes: [MessageAttribute]) -> [MessageAttribute] { + return attributes.filter { attribute in + switch attribute { + case _ as TextEntitiesMessageAttribute: + return true + case _ as InlineBotMessageAttribute: + return true + default: + return false + } + } +} + +func opportunisticallyTransformMessageWithMedia(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia, mediaReference: AnyMediaReference, userInteractive: Bool) -> Signal { + return transformOutgoingMessageMedia(postbox, network, mediaReference, userInteractive) + |> timeout(2.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil)) +} + +private func forwardedMessageToBeReuploaded(transaction: Transaction, id: MessageId) -> Message? { + if let message = transaction.getMessage(id) { + if message.id.namespace != Namespaces.Message.Cloud { + return message + } else { + return nil + } + } else { + return nil + } +} + +private func opportunisticallyTransformOutgoingMedia(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia, messages: [EnqueueMessage], userInteractive: Bool) -> Signal<[(Bool, EnqueueMessage)], NoError> { + var hasMedia = false + loop: for message in messages { + switch message { + case let .message(_, _, mediaReference, _, _): + if mediaReference != nil { + hasMedia = true + break loop + } + case .forward: + break + } + } + + if !hasMedia { + return .single(messages.map { (true, $0) }) + } + + var signals: [Signal<(Bool, EnqueueMessage), NoError>] = [] + for message in messages { + switch message { + case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): + if let mediaReference = mediaReference { + signals.append(opportunisticallyTransformMessageWithMedia(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, mediaReference: mediaReference, userInteractive: userInteractive) + |> map { result -> (Bool, EnqueueMessage) in + if let result = result { + return (true, .message(text: text, attributes: attributes, mediaReference: .standalone(media: result.media), replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey)) + } else { + return (false, .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey)) + } + }) + } else { + signals.append(.single((false, message))) + } + case .forward: + signals.append(.single((false, message))) + } + } + return combineLatest(signals) +} + +public func enqueueMessages(account: Account, peerId: PeerId, messages: [EnqueueMessage]) -> Signal<[MessageId?], NoError> { + let signal: Signal<[(Bool, EnqueueMessage)], NoError> + if let transformOutgoingMessageMedia = account.transformOutgoingMessageMedia { + signal = opportunisticallyTransformOutgoingMedia(network: account.network, postbox: account.postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messages: messages, userInteractive: true) + } else { + signal = .single(messages.map { (false, $0) }) + } + return signal + |> mapToSignal { messages -> Signal<[MessageId?], NoError> in + return account.postbox.transaction { transaction -> [MessageId?] in + return enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages) + } + } +} + +public func enqueueMessagesToMultiplePeers(account: Account, peerIds: [PeerId], messages: [EnqueueMessage]) -> Signal<[MessageId], NoError> { + let signal: Signal<[(Bool, EnqueueMessage)], NoError> + if let transformOutgoingMessageMedia = account.transformOutgoingMessageMedia { + signal = opportunisticallyTransformOutgoingMedia(network: account.network, postbox: account.postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messages: messages, userInteractive: true) + } else { + signal = .single(messages.map { (false, $0) }) + } + return signal + |> mapToSignal { messages -> Signal<[MessageId], NoError> in + return account.postbox.transaction { transaction -> [MessageId] in + var messageIds: [MessageId] = [] + for peerId in peerIds { + for id in enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages, disableAutoremove: false) { + if let id = id { + messageIds.append(id) + } + } + } + return messageIds + } + } +} + +public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal { + return account.postbox.transaction { transaction -> Void in + var removeMessageIds: [MessageId] = [] + for (peerId, ids) in messagesIdsGroupedByPeerId(messageIds) { + var messages: [EnqueueMessage] = [] + for id in ids { + if let message = transaction.getMessage(id), !message.flags.contains(.Incoming) { + removeMessageIds.append(id) + + var filteredAttributes: [MessageAttribute] = [] + var replyToMessageId: MessageId? + inner: for attribute in message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + replyToMessageId = attribute.messageId + } else if attribute is OutgoingMessageInfoAttribute { + continue inner + } else { + filteredAttributes.append(attribute) + } + } + + messages.append(.message(text: message.text, attributes: filteredAttributes, mediaReference: message.media.first.flatMap(AnyMediaReference.standalone), replyToMessageId: replyToMessageId, localGroupingKey: message.groupingKey)) + } + } + let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages.map { (false, $0) }) + } + deleteMessages(transaction: transaction, mediaBox: account.postbox.mediaBox, ids: removeMessageIds) + } +} + +func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, messages: [(Bool, EnqueueMessage)], disableAutoremove: Bool = false) -> [MessageId?] { + var updatedMessages: [(Bool, EnqueueMessage)] = [] + outer: for (transformedMedia, message) in messages { + switch message { + case let .message(desc): + if let replyToMessageId = desc.replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) { + var canBeForwarded = true + if replyMessage.id.namespace != Namespaces.Message.Cloud { + canBeForwarded = false + } + inner: for media in replyMessage.media { + if media is TelegramMediaAction { + canBeForwarded = false + break inner + } + } + if canBeForwarded { + updatedMessages.append((true, .forward(source: replyToMessageId, grouping: .none))) + } + } + case let .forward(sourceId, _): + if let sourceMessage = forwardedMessageToBeReuploaded(transaction: transaction, id: sourceId) { + var mediaReference: AnyMediaReference? + if sourceMessage.id.peerId.namespace == Namespaces.Peer.SecretChat { + if let media = sourceMessage.media.first { + mediaReference = .standalone(media: media) + } + } + updatedMessages.append((transformedMedia, .message(text: sourceMessage.text, attributes: sourceMessage.attributes, mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))) + continue outer + } + } + updatedMessages.append((transformedMedia, message)) + } + + if let peer = transaction.getPeer(peerId), let accountPeer = transaction.getPeer(account.peerId) { + var storeMessages: [StoreMessage] = [] + var timestamp = Int32(account.network.context.globalTime()) + switch peerId.namespace { + case Namespaces.Peer.CloudChannel, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudUser: + if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) { + timestamp = max(timestamp, topIndex.timestamp) + } + default: + break + } + + var addedHashtags: [String] = [] + + var localGroupingKeyBySourceKey: [Int64: Int64] = [:] + + var globallyUniqueIds: [Int64] = [] + for (transformedMedia, message) in updatedMessages { + var attributes: [MessageAttribute] = [] + var flags = StoreMessageFlags() + flags.insert(.Unsent) + + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + var infoFlags = OutgoingMessageInfoFlags() + if transformedMedia { + infoFlags.insert(.transformedMedia) + } + attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: infoFlags, acknowledged: false)) + globallyUniqueIds.append(randomId) + + switch message { + case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey): + if let peer = peer as? TelegramSecretChat { + var isAction = false + if let _ = mediaReference?.media as? TelegramMediaAction { + isAction = true + } + if !disableAutoremove, let messageAutoremoveTimeout = peer.messageAutoremoveTimeout, !isAction { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: messageAutoremoveTimeout, countdownBeginTime: nil)) + } + } + + attributes.append(contentsOf: filterMessageAttributesForOutgoingMessage(requestedAttributes)) + + if let replyToMessageId = replyToMessageId, replyToMessageId.peerId == peerId { + attributes.append(ReplyMessageAttribute(messageId: replyToMessageId)) + } + var mediaList: [Media] = [] + if let mediaReference = mediaReference { + let augmentedMedia = augmentMediaWithReference(mediaReference) + mediaList.append(augmentedMedia) + } + + if let file = mediaReference?.media as? TelegramMediaFile, file.isVoice || file.isInstantVideo { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.SecretChat { + attributes.append(ConsumableContentMessageAttribute(consumed: false)) + } + } + if let peer = peer as? TelegramChannel { + switch peer.info { + case let .broadcast(info): + attributes.append(ViewCountMessageAttribute(count: 1)) + if info.flags.contains(.messagesShouldHaveSignatures) { + attributes.append(AuthorSignatureMessageAttribute(signature: accountPeer.debugDisplayTitle)) + } + case .group: + break + } + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + var maybeNsText: NSString? + for entity in attribute.entities { + if case .Hashtag = entity.type { + let nsText: NSString + if let maybeNsText = maybeNsText { + nsText = maybeNsText + } else { + nsText = text as NSString + maybeNsText = nsText + } + var entityRange = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) + if entityRange.location + entityRange.length > nsText.length { + entityRange.location = max(0, nsText.length - entityRange.length) + entityRange.length = nsText.length - entityRange.location + } + if entityRange.length > 1 { + entityRange.location += 1 + entityRange.length -= 1 + let hashtag = nsText.substring(with: entityRange) + addedHashtags.append(hashtag) + } + } + } + break + } + } + + let authorId: PeerId? + if let peer = peer as? TelegramChannel, case let .broadcast(info) = peer.info { + authorId = peer.id + } else { + authorId = account.peerId + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: false, attributes: attributes, media: mediaList, textEntities: entitiesAttribute?.entities) + + var localTags: LocalMessageTags = [] + for media in mediaList { + if let media = media as? TelegramMediaMap, media.liveBroadcastingTimeout != nil { + localTags.insert(.OutgoingLiveLocation) + } + } + + storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, groupingKey: localGroupingKey, timestamp: timestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: localTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList)) + case let .forward(source, grouping): + let sourceMessage = transaction.getMessage(source) + if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] { + if let peer = peer as? TelegramSecretChat { + var isAction = false + var mediaDuration: Int32? + for media in sourceMessage.media { + if let _ = media as? TelegramMediaAction { + isAction = true + } else if let file = media as? TelegramMediaFile, let duration = file.duration { + mediaDuration = duration + } + } + if !disableAutoremove, let messageAutoremoveTimeout = peer.messageAutoremoveTimeout, !isAction { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: messageAutoremoveTimeout, countdownBeginTime: nil)) + } + } + + var forwardInfo: StoreMessageForwardInfo? + + if sourceMessage.id.namespace == Namespaces.Message.Cloud && peerId.namespace != Namespaces.Peer.SecretChat { + attributes.append(ForwardSourceInfoAttribute(messageId: sourceMessage.id)) + + if peerId == account.peerId { + attributes.append(SourceReferenceMessageAttribute(messageId: sourceMessage.id)) + } + + attributes.append(contentsOf: filterMessageAttributesForForwardedMessage(sourceMessage.attributes)) + + var sourceReplyMarkup: ReplyMarkupMessageAttribute? = nil + var sourceSentViaBot = false + for attribute in attributes { + if let attribute = attribute as? ReplyMarkupMessageAttribute { + sourceReplyMarkup = attribute + } else if let _ = attribute as? InlineBotMessageAttribute { + sourceSentViaBot = true + } + } + + if let sourceReplyMarkup = sourceReplyMarkup { + var rows: [ReplyMarkupRow] = [] + loop: for row in sourceReplyMarkup.rows { + var buttons: [ReplyMarkupButton] = [] + for button in row.buttons { + if case .url = button.action { + buttons.append(button) + } else if case .urlAuth = button.action { + buttons.append(button) + } else if case let .switchInline(samePeer, query) = button.action, sourceSentViaBot { + let samePeer = samePeer && peerId == sourceMessage.id.peerId + let updatedButton = ReplyMarkupButton(title: button.titleWhenForwarded ?? button.title, titleWhenForwarded: button.titleWhenForwarded, action: .switchInline(samePeer: samePeer, query: query)) + buttons.append(updatedButton) + } else { + rows.removeAll() + break loop + } + } + rows.append(ReplyMarkupRow(buttons: buttons)) + } + + if !rows.isEmpty { + attributes.append(ReplyMarkupMessageAttribute(rows: rows, flags: sourceReplyMarkup.flags)) + } + } + + if let sourceForwardInfo = sourceMessage.forwardInfo { + forwardInfo = StoreMessageForwardInfo(authorId: sourceForwardInfo.author?.id, sourceId: sourceForwardInfo.source?.id, sourceMessageId: sourceForwardInfo.sourceMessageId, date: sourceForwardInfo.date, authorSignature: sourceForwardInfo.authorSignature) + } else { + if sourceMessage.id.peerId != account.peerId { + var hasHiddenForwardMedia = false + for media in sourceMessage.media { + if let file = media as? TelegramMediaFile { + if file.isMusic { + hasHiddenForwardMedia = true + } + } + } + + if !hasHiddenForwardMedia { + var sourceId: PeerId? = nil + var sourceMessageId: MessageId? = nil + if let peer = messageMainPeer(sourceMessage) as? TelegramChannel, case .broadcast = peer.info { + sourceId = peer.id + sourceMessageId = sourceMessage.id + } + + var authorSignature: String? + for attribute in sourceMessage.attributes { + if let attribute = attribute as? AuthorSignatureMessageAttribute { + authorSignature = attribute.signature + break + } + } + + forwardInfo = StoreMessageForwardInfo(authorId: author.id, sourceId: sourceId, sourceMessageId: sourceMessageId, date: sourceMessage.timestamp, authorSignature: authorSignature) + } + } else { + forwardInfo = nil + } + } + } else { + attributes.append(contentsOf: filterMessageAttributesForOutgoingMessage(sourceMessage.attributes)) + } + + let authorId: PeerId? + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + authorId = peer.id + } else { + authorId = account.peerId + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + break + } + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: false, attributes: attributes, media: sourceMessage.media, textEntities: entitiesAttribute?.entities) + + let localGroupingKey: Int64? + switch grouping { + case .none: + localGroupingKey = nil + case .auto: + if let groupingKey = sourceMessage.groupingKey { + if let generatedKey = localGroupingKeyBySourceKey[groupingKey] { + localGroupingKey = generatedKey + } else { + let generatedKey = arc4random64() + localGroupingKeyBySourceKey[groupingKey] = generatedKey + localGroupingKey = generatedKey + } + } else { + localGroupingKey = nil + } + } + + var augmentedMediaList = sourceMessage.media.map { media -> Media in + return augmentMediaWithReference(.message(message: MessageReference(sourceMessage), media: media)) + } + + if peerId.namespace == Namespaces.Peer.SecretChat { + augmentedMediaList = augmentedMediaList.map(convertForwardedMediaForSecretChat) + } + + storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, groupingKey: localGroupingKey, timestamp: timestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: sourceMessage.text, attributes: attributes, media: augmentedMediaList)) + } + } + } + var messageIds: [MessageId?] = [] + if !storeMessages.isEmpty { + let globallyUniqueIdToMessageId = transaction.addMessages(storeMessages, location: .Random) + for globallyUniqueId in globallyUniqueIds { + messageIds.append(globallyUniqueIdToMessageId[globallyUniqueId]) + } + + if peerId.namespace == Namespaces.Peer.CloudUser { + if case .notIncluded = transaction.getPeerChatListInclusion(peerId) { + transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: .root, pinningIndex: nil, minTimestamp: nil)) + } + } + } + for hashtag in addedHashtags { + addRecentlyUsedHashtag(transaction: transaction, string: hashtag) + } + return messageIds + } else { + return [] + } +} diff --git a/submodules/TelegramCore/TelegramCore/ExportMessageLink.swift b/submodules/TelegramCore/TelegramCore/ExportMessageLink.swift new file mode 100644 index 0000000000..1f80968584 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ExportMessageLink.swift @@ -0,0 +1,30 @@ + +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + + +public func exportMessageLink(account: Account, peerId: PeerId, messageId: MessageId) -> Signal { + return account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> mapToSignal { peer -> Signal in + if let peer = peer, let input = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.exportMessageLink(channel: input, id: messageId.id, grouped: .boolTrue)) |> mapError { _ in return } + |> map { res in + switch res { + case let .exportedMessageLink(link, _): + return link + } + } |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + return .single(nil) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ExportedInvitation.swift b/submodules/TelegramCore/TelegramCore/ExportedInvitation.swift new file mode 100644 index 0000000000..1e60aa6243 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ExportedInvitation.swift @@ -0,0 +1,37 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct ExportedInvitation: PostboxCoding, Equatable { + public let link: String + + init(link: String) { + self.link = link + } + + public init(decoder: PostboxDecoder) { + self.link = decoder.decodeStringForKey("l", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.link, forKey: "l") + } + + public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool { + return lhs.link == rhs.link + } +} + +extension ExportedInvitation { + init?(apiExportedInvite: Api.ExportedChatInvite) { + switch apiExportedInvite { + case .chatInviteEmpty: + return nil + case let .chatInviteExported(link): + self = ExportedInvitation(link: link) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/FeaturedStickerPack.swift b/submodules/TelegramCore/TelegramCore/FeaturedStickerPack.swift new file mode 100644 index 0000000000..d92c863c5a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FeaturedStickerPack.swift @@ -0,0 +1,50 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct FeaturedStickerPackItemId { + public let rawValue: MemoryBuffer + public let packId: Int64 + + init(_ rawValue: MemoryBuffer) { + self.rawValue = rawValue + assert(rawValue.length == 8) + var idValue: Int64 = 0 + memcpy(&idValue, rawValue.memory, 8) + self.packId = idValue + } + + init(_ packId: Int64) { + self.packId = packId + var idValue: Int64 = packId + self.rawValue = MemoryBuffer(memory: malloc(8)!, capacity: 8, length: 8, freeWhenDone: true) + memcpy(self.rawValue.memory, &idValue, 8) + } +} + +public final class FeaturedStickerPackItem: OrderedItemListEntryContents { + public let info: StickerPackCollectionInfo + public let topItems: [StickerPackItem] + public let unread: Bool + + init(info: StickerPackCollectionInfo, topItems: [StickerPackItem], unread: Bool) { + self.info = info + self.topItems = topItems + self.unread = unread + } + + public init(decoder: PostboxDecoder) { + self.info = decoder.decodeObjectForKey("i") as! StickerPackCollectionInfo + self.topItems = decoder.decodeObjectArrayForKey("t") + self.unread = decoder.decodeInt32ForKey("u", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.info, forKey: "i") + encoder.encodeObjectArray(self.topItems, forKey: "t") + encoder.encodeInt32(self.unread ? 1 : 0, forKey: "u") + } +} diff --git a/submodules/TelegramCore/TelegramCore/Fetch.swift b/submodules/TelegramCore/TelegramCore/Fetch.swift new file mode 100644 index 0000000000..f26389e16b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Fetch.swift @@ -0,0 +1,58 @@ +import Foundation + +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +import Photos +#endif + +private func fetchCloudMediaLocation(account: Account, resource: TelegramMediaResource, datacenterId: Int, size: Int?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { + return multipartFetch(postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, resource: resource, datacenterId: datacenterId, size: size, intervals: intervals, parameters: parameters) +} + +private func fetchLocalFileResource(path: String, move: Bool) -> Signal { + return Signal { subscriber in + if move { + subscriber.putNext(.moveLocalFile(path: path)) + subscriber.putCompletion() + } else { + if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) { + subscriber.putNext(.dataPart(resourceOffset: 0, data: data, range: 0 ..< data.count, complete: true)) + subscriber.putCompletion() + } else { + subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false)) + } + } + return EmptyDisposable + } +} + +func fetchResource(account: Account, resource: MediaResource, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal? { + if let _ = resource as? EmptyMediaResource { + return .single(.reset) + |> then(.never()) + } else if let secretFileResource = resource as? SecretFileMediaResource { + return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false)) + |> then(fetchSecretFileResource(account: account, resource: secretFileResource, intervals: intervals, parameters: parameters)) + } else if let cloudResource = resource as? TelegramMultipartFetchableResource { + return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false)) + |> then(fetchCloudMediaLocation(account: account, resource: cloudResource, datacenterId: cloudResource.datacenterId, size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: parameters)) + } else if let webFileResource = resource as? WebFileReferenceMediaResource { + return currentWebDocumentsHostDatacenterId(postbox: account.postbox, isTestingEnvironment: account.testingEnvironment) + |> introduceError(MediaResourceDataFetchError.self) + |> mapToSignal { datacenterId -> Signal in + return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false)) + |> then(fetchCloudMediaLocation(account: account, resource: webFileResource, datacenterId: Int(datacenterId), size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: parameters)) + } + } else if let localFileResource = resource as? LocalFileReferenceMediaResource { + return fetchLocalFileResource(path: localFileResource.localFilePath, move: localFileResource.isUniquelyReferencedTemporaryFile) + |> introduceError(MediaResourceDataFetchError.self) + } else if let httpReference = resource as? HttpReferenceMediaResource { + return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false)) + |> then(fetchHttpResource(url: httpReference.url)) + } + return nil +} diff --git a/submodules/TelegramCore/TelegramCore/FetchChatList.swift b/submodules/TelegramCore/TelegramCore/FetchChatList.swift new file mode 100644 index 0000000000..ce48d62079 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FetchChatList.swift @@ -0,0 +1,393 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +enum FetchChatListLocation { + case general + case group(PeerGroupId) +} + +struct ParsedDialogs { + let itemIds: [PeerId] + let peers: [Peer] + let peerPresences: [PeerId: PeerPresence] + + let notificationSettings: [PeerId: PeerNotificationSettings] + let readStates: [PeerId: [MessageId.Namespace: PeerReadState]] + let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] + let chatStates: [PeerId: PeerChatState] + let topMessageIds: [PeerId: MessageId] + let storeMessages: [StoreMessage] + + let lowerNonPinnedIndex: MessageIndex? + let referencedFolders: [PeerGroupId: PeerGroupUnreadCountersSummary] +} + +private func extractDialogsData(dialogs: Api.messages.Dialogs) -> (apiDialogs: [Api.Dialog], apiMessages: [Api.Message], apiChats: [Api.Chat], apiUsers: [Api.User], apiIsAtLowestBoundary: Bool) { + switch dialogs { + case let .dialogs(dialogs, messages, chats, users): + return (dialogs, messages, chats, users, true) + case let .dialogsSlice(_, dialogs, messages, chats, users): + return (dialogs, messages, chats, users, false) + case .dialogsNotModified: + assertionFailure() + return ([], [], [], [], true) + } +} + +private func extractDialogsData(peerDialogs: Api.messages.PeerDialogs) -> (apiDialogs: [Api.Dialog], apiMessages: [Api.Message], apiChats: [Api.Chat], apiUsers: [Api.User], apiIsAtLowestBoundary: Bool) { + switch peerDialogs { + case let .peerDialogs(dialogs, messages, chats, users, _): + return (dialogs, messages, chats, users, false) + } +} + +private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message], apiChats: [Api.Chat], apiUsers: [Api.User], apiIsAtLowestBoundary: Bool) -> ParsedDialogs { + var notificationSettings: [PeerId: PeerNotificationSettings] = [:] + var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] + var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] + var chatStates: [PeerId: PeerChatState] = [:] + var topMessageIds: [PeerId: MessageId] = [:] + + var storeMessages: [StoreMessage] = [] + var nonPinnedDialogsTopMessageIds = Set() + + var referencedFolders: [PeerGroupId: PeerGroupUnreadCountersSummary] = [:] + var itemIds: [PeerId] = [] + + var peers: [PeerId: Peer] = [:] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in apiChats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + for user in apiUsers { + let telegramUser = TelegramUser(user: user) + peers[telegramUser.id] = telegramUser + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + for dialog in apiDialogs { + let apiPeer: Api.Peer + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiTopMessage: Int32 + let apiUnreadCount: Int32 + let apiMarkedUnread: Bool + let apiUnreadMentionsCount: Int32 + var apiChannelPts: Int32? + let apiNotificationSettings: Api.PeerNotifySettings + switch dialog { + case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _, _): + if let peer = peers[peer.peerId] { + var isExluded = false + if let group = peer as? TelegramGroup { + if group.flags.contains(.deactivated) { + isExluded = true + } + } + if !isExluded { + itemIds.append(peer.id) + } + } + apiPeer = peer + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + apiUnreadMentionsCount = unreadMentionsCount + apiNotificationSettings = peerNotificationSettings + apiChannelPts = pts + let isPinned = (flags & (1 << 2)) != 0 + if !isPinned { + nonPinnedDialogsTopMessageIds.insert(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: topMessage)) + } + let peerId: PeerId + switch apiPeer { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + if readStates[peerId] == nil { + readStates[peerId] = [:] + } + readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) + + if apiTopMessage != 0 { + mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage)) + topMessageIds[peerId] = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: apiTopMessage) + } + + if let apiChannelPts = apiChannelPts { + chatStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: nil) + } + + notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) + case let .dialogFolder(dialogFolder): + switch dialogFolder.folder { + case let .folder(folder): + referencedFolders[PeerGroupId(rawValue: folder.id)] = PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: dialogFolder.unreadMutedMessagesCount, chatCount: dialogFolder.unreadMutedPeersCount)) + } + } + } + + var lowerNonPinnedIndex: MessageIndex? + + for message in apiMessages { + if let storeMessage = StoreMessage(apiMessage: message) { + var updatedStoreMessage = storeMessage + if case let .Id(id) = storeMessage.id { + if let channelState = chatStates[id.peerId] as? ChannelState { + var updatedAttributes = storeMessage.attributes + updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) + } + + if !apiIsAtLowestBoundary, nonPinnedDialogsTopMessageIds.contains(id) { + let index = MessageIndex(id: id, timestamp: storeMessage.timestamp) + if lowerNonPinnedIndex == nil || lowerNonPinnedIndex! > index { + lowerNonPinnedIndex = index + } + } + } + storeMessages.append(updatedStoreMessage) + } + } + + return ParsedDialogs( + itemIds: itemIds, + peers: Array(peers.values), + peerPresences: peerPresences, + + notificationSettings: notificationSettings, + readStates: readStates, + mentionTagSummaries: mentionTagSummaries, + chatStates: chatStates, + topMessageIds: topMessageIds, + storeMessages: storeMessages, + + lowerNonPinnedIndex: lowerNonPinnedIndex, + referencedFolders: referencedFolders + ) +} + +struct FetchedChatList { + let chatPeerIds: [PeerId] + let peers: [Peer] + let peerPresences: [PeerId: PeerPresence] + let notificationSettings: [PeerId: PeerNotificationSettings] + let readStates: [PeerId: [MessageId.Namespace: PeerReadState]] + let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] + let chatStates: [PeerId: PeerChatState] + let storeMessages: [StoreMessage] + let topMessageIds: [PeerId: MessageId] + + let lowerNonPinnedIndex: MessageIndex? + + let pinnedItemIds: [PeerId]? + let folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary] + let peerGroupIds: [PeerId: PeerGroupId] +} + +func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLocation, upperBound: MessageIndex, hash: Int32, limit: Int32) -> Signal { + return postbox.stateView() + |> mapToSignal { view -> Signal in + if let state = view.state as? AuthorizedAccountState { + return .single(state) + } else { + return .complete() + } + } + |> take(1) + |> mapToSignal { _ -> Signal in + let offset: Signal<(Int32, Int32, Api.InputPeer), NoError> + if upperBound.id.peerId.namespace == Namespaces.Peer.Empty { + offset = single((0, 0, Api.InputPeer.inputPeerEmpty), NoError.self) + } else { + offset = postbox.loadedPeerWithId(upperBound.id.peerId) + |> take(1) + |> map { peer in + return (upperBound.timestamp, upperBound.id.id, apiInputPeer(peer) ?? .inputPeerEmpty) + } + } + + return offset + |> mapToSignal { (timestamp, id, peer) -> Signal in + let additionalPinnedChats: Signal + if case .inputPeerEmpty = peer, timestamp == 0 { + let folderId: Int32 + switch location { + case .general: + folderId = 0 + case let .group(groupId): + folderId = groupId.rawValue + } + additionalPinnedChats = network.request(Api.functions.messages.getPinnedDialogs(folderId: folderId)) + |> retryRequest + |> map(Optional.init) + } else { + additionalPinnedChats = .single(nil) + } + + var flags: Int32 = 1 << 1 + let requestFolderId: Int32 + + switch location { + case .general: + requestFolderId = 0 + case let .group(groupId): + flags |= 1 << 0 + requestFolderId = groupId.rawValue + } + let requestChats = network.request(Api.functions.messages.getDialogs(flags: flags, folderId: requestFolderId, offsetDate: timestamp, offsetId: id, offsetPeer: peer, limit: limit, hash: hash)) + |> retryRequest + + return combineLatest(requestChats, additionalPinnedChats) + |> mapToSignal { remoteChats, pinnedChats -> Signal in + if case .dialogsNotModified = remoteChats { + return .single(nil) + } + let extractedRemoteDialogs = extractDialogsData(dialogs: remoteChats) + let parsedRemoteChats = parseDialogs(apiDialogs: extractedRemoteDialogs.apiDialogs, apiMessages: extractedRemoteDialogs.apiMessages, apiChats: extractedRemoteDialogs.apiChats, apiUsers: extractedRemoteDialogs.apiUsers, apiIsAtLowestBoundary: extractedRemoteDialogs.apiIsAtLowestBoundary) + var parsedPinnedChats: ParsedDialogs? + if let pinnedChats = pinnedChats { + let extractedPinnedChats = extractDialogsData(peerDialogs: pinnedChats) + parsedPinnedChats = parseDialogs(apiDialogs: extractedPinnedChats.apiDialogs, apiMessages: extractedPinnedChats.apiMessages, apiChats: extractedPinnedChats.apiChats, apiUsers: extractedPinnedChats.apiUsers, apiIsAtLowestBoundary: extractedPinnedChats.apiIsAtLowestBoundary) + } + + var combinedReferencedFolders = Set() + combinedReferencedFolders.formUnion(parsedRemoteChats.referencedFolders.keys) + if let parsedPinnedChats = parsedPinnedChats { + combinedReferencedFolders.formUnion(Set(parsedPinnedChats.referencedFolders.keys)) + } + + var folderSignals: [Signal<(PeerGroupId, ParsedDialogs), NoError>] = [] + if case .general = location { + for groupId in combinedReferencedFolders { + let flags: Int32 = 1 << 1 + let requestFeed = network.request(Api.functions.messages.getDialogs(flags: flags, folderId: groupId.rawValue, offsetDate: 0, offsetId: 0, offsetPeer: .inputPeerEmpty, limit: 32, hash: 0)) + |> retryRequest + |> map { result -> (PeerGroupId, ParsedDialogs) in + let extractedData = extractDialogsData(dialogs: result) + let parsedChats = parseDialogs(apiDialogs: extractedData.apiDialogs, apiMessages: extractedData.apiMessages, apiChats: extractedData.apiChats, apiUsers: extractedData.apiUsers, apiIsAtLowestBoundary: extractedData.apiIsAtLowestBoundary) + return (groupId, parsedChats) + } + folderSignals.append(requestFeed) + } + } + + return combineLatest(folderSignals) + |> map { folders -> FetchedChatList? in + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + var notificationSettings: [PeerId: PeerNotificationSettings] = [:] + var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] + var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] + var chatStates: [PeerId: PeerChatState] = [:] + var storeMessages: [StoreMessage] = [] + var topMessageIds: [PeerId: MessageId] = [:] + + peers.append(contentsOf: parsedRemoteChats.peers) + peerPresences.merge(parsedRemoteChats.peerPresences, uniquingKeysWith: { _, updated in updated }) + notificationSettings.merge(parsedRemoteChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) + readStates.merge(parsedRemoteChats.readStates, uniquingKeysWith: { _, updated in updated }) + mentionTagSummaries.merge(parsedRemoteChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) + chatStates.merge(parsedRemoteChats.chatStates, uniquingKeysWith: { _, updated in updated }) + storeMessages.append(contentsOf: parsedRemoteChats.storeMessages) + topMessageIds.merge(parsedRemoteChats.topMessageIds, uniquingKeysWith: { _, updated in updated }) + + if let parsedPinnedChats = parsedPinnedChats { + peers.append(contentsOf: parsedPinnedChats.peers) + peerPresences.merge(parsedPinnedChats.peerPresences, uniquingKeysWith: { _, updated in updated }) + notificationSettings.merge(parsedPinnedChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) + readStates.merge(parsedPinnedChats.readStates, uniquingKeysWith: { _, updated in updated }) + mentionTagSummaries.merge(parsedPinnedChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) + chatStates.merge(parsedPinnedChats.chatStates, uniquingKeysWith: { _, updated in updated }) + storeMessages.append(contentsOf: parsedPinnedChats.storeMessages) + topMessageIds.merge(parsedPinnedChats.topMessageIds, uniquingKeysWith: { _, updated in updated }) + } + + var peerGroupIds: [PeerId: PeerGroupId] = [:] + + if case let .group(groupId) = location { + for peerId in parsedRemoteChats.itemIds { + peerGroupIds[peerId] = groupId + } + } + + for (groupId, folderChats) in folders { + for peerId in folderChats.itemIds { + peerGroupIds[peerId] = groupId + } + peers.append(contentsOf: folderChats.peers) + peerPresences.merge(folderChats.peerPresences, uniquingKeysWith: { _, updated in updated }) + notificationSettings.merge(folderChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) + readStates.merge(folderChats.readStates, uniquingKeysWith: { _, updated in updated }) + mentionTagSummaries.merge(folderChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) + chatStates.merge(folderChats.chatStates, uniquingKeysWith: { _, updated in updated }) + storeMessages.append(contentsOf: folderChats.storeMessages) + } + + var pinnedItemIds: [PeerId]? + if let parsedPinnedChats = parsedPinnedChats { + var array: [PeerId] = [] + for peerId in parsedPinnedChats.itemIds { + if case let .group(groupId) = location { + peerGroupIds[peerId] = groupId + } + array.append(peerId) + } + pinnedItemIds = array + } + + var folderSummaries: [PeerGroupId: PeerGroupUnreadCountersSummary] = [:] + for (groupId, summary) in parsedRemoteChats.referencedFolders { + folderSummaries[groupId] = summary + } + if let parsedPinnedChats = parsedPinnedChats { + for (groupId, summary) in parsedPinnedChats.referencedFolders { + folderSummaries[groupId] = summary + } + } + + return FetchedChatList( + chatPeerIds: parsedRemoteChats.itemIds + (pinnedItemIds ?? []), + peers: peers, + peerPresences: peerPresences, + notificationSettings: notificationSettings, + readStates: readStates, + mentionTagSummaries: mentionTagSummaries, + chatStates: chatStates, + storeMessages: storeMessages, + topMessageIds: topMessageIds, + + lowerNonPinnedIndex: parsedRemoteChats.lowerNonPinnedIndex, + + pinnedItemIds: pinnedItemIds, + folderSummaries: folderSummaries, + peerGroupIds: peerGroupIds + ) + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/FetchHttpResource.swift b/submodules/TelegramCore/TelegramCore/FetchHttpResource.swift new file mode 100644 index 0000000000..1306387511 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FetchHttpResource.swift @@ -0,0 +1,38 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func fetchHttpResource(url: String) -> Signal { + if let url = URL(string: url) { + let signal = MTHttpRequestOperation.data(forHttpUrl: url)! + return Signal { subscriber in + subscriber.putNext(.reset) + let disposable = signal.start(next: { next in + let data = next as! Data + let fetchResult: MediaResourceDataFetchResult = .dataPart(resourceOffset: 0, data: data, range: 0 ..< data.count, complete: true) + subscriber.putNext(fetchResult) + subscriber.putCompletion() + }, error: { _ in + subscriber.putError(.generic) + }, completed: { + }) + + return ActionDisposable { + disposable?.dispose() + } + } + } else { + return .never() + } +} diff --git a/submodules/TelegramCore/TelegramCore/FetchSecretFileResource.swift b/submodules/TelegramCore/TelegramCore/FetchSecretFileResource.swift new file mode 100644 index 0000000000..f53a699d35 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FetchSecretFileResource.swift @@ -0,0 +1,18 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func fetchSecretFileResource(account: Account, resource: SecretFileMediaResource, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { + return multipartFetch(postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, resource: resource, datacenterId: resource.datacenterId, size: resource.size, intervals: intervals, parameters: parameters, encryptionKey: resource.key, decryptedSize: resource.decryptedSize) +} diff --git a/submodules/TelegramCore/TelegramCore/FetchedMediaResource.swift b/submodules/TelegramCore/TelegramCore/FetchedMediaResource.swift new file mode 100644 index 0000000000..8f5121035e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FetchedMediaResource.swift @@ -0,0 +1,1090 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public struct MessageReference: PostboxCoding, Hashable, Equatable { + let content: MessageReferenceContent + + public var peer: PeerReference? { + switch content { + case .none: + return nil + case let .message(peer, _, _, _, _): + return peer + } + } + + public var timestamp: Int32? { + switch content { + case .none: + return nil + case let .message(_, _, timestamp, _, _): + return timestamp + } + } + + public var isIncoming: Bool? { + switch content { + case .none: + return nil + case let .message(_, _, _, incoming, _): + return incoming + } + } + + public var isSecret: Bool? { + switch content { + case .none: + return nil + case let .message(_, _, _, _, secret): + return secret + } + } + + public init(_ message: Message) { + if message.id.namespace != Namespaces.Message.Local, let peer = message.peers[message.id.peerId], let inputPeer = PeerReference(peer) { + self.content = .message(peer: inputPeer, id: message.id, timestamp: message.timestamp, incoming: message.flags.contains(.Incoming), secret: message.containsSecretMedia) + } else { + self.content = .none + } + } + + public init(peer: Peer, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool) { + if let inputPeer = PeerReference(peer) { + self.content = .message(peer: inputPeer, id: id, timestamp: timestamp, incoming: incoming, secret: secret) + } else { + self.content = .none + } + } + + public init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { MessageReferenceContent(decoder: $0) }) as! MessageReferenceContent + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +enum MessageReferenceContent: PostboxCoding, Hashable, Equatable { + case none + case message(peer: PeerReference, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool) + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_r", orElse: 0) { + case 0: + self = .none + case 1: + self = .message(peer: decoder.decodeObjectForKey("p", decoder: { PeerReference(decoder: $0) }) as! PeerReference, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0)), timestamp: 0, incoming: false, secret: false) + default: + assertionFailure() + self = .none + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case .none: + encoder.encodeInt32(0, forKey: "_r") + case let .message(peer, id, _, _, _): + encoder.encodeInt32(1, forKey: "_r") + encoder.encodeObject(peer, forKey: "p") + encoder.encodeInt64(id.peerId.toInt64(), forKey: "i.p") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt32(id.id, forKey: "i.i") + } + } +} + +public struct WebpageReference: PostboxCoding, Hashable, Equatable { + let content: WebpageReferenceContent + + public init(_ webPage: TelegramMediaWebpage) { + if case let .Loaded(content) = webPage.content { + self.content = .webPage(id: webPage.webpageId.id, url: content.url) + } else { + self.content = .none + } + } + + public init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { WebpageReferenceContent(decoder: $0) }) as! WebpageReferenceContent + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +enum WebpageReferenceContent: PostboxCoding, Hashable, Equatable { + case none + case webPage(id: Int64, url: String) + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_r", orElse: 0) { + case 0: + self = .none + case 1: + self = .webPage(id: decoder.decodeInt64ForKey("i", orElse: 0), url: decoder.decodeStringForKey("u", orElse: "")) + default: + assertionFailure() + self = .none + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case .none: + encoder.encodeInt32(0, forKey: "_r") + case let .webPage(id, url): + encoder.encodeInt32(1, forKey: "_r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeString(url, forKey: "u") + } + } +} + +public enum AnyMediaReference: Equatable { + case standalone(media: Media) + case message(message: MessageReference, media: Media) + case webPage(webPage: WebpageReference, media: Media) + case stickerPack(stickerPack: StickerPackReference, media: Media) + case savedGif(media: Media) + + public static func ==(lhs: AnyMediaReference, rhs: AnyMediaReference) -> Bool { + switch lhs { + case let .standalone(lhsMedia): + if case let .standalone(rhsMedia) = rhs, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } + case let .message(lhsMessage, lhsMedia): + if case let .message(rhsMessage, rhsMedia) = rhs, lhsMessage == rhsMessage, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } + case let .webPage(lhsWebPage, lhsMedia): + if case let .webPage(rhsWebPage, rhsMedia) = rhs, lhsWebPage == rhsWebPage, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } + case let .stickerPack(lhsStickerPack, lhsMedia): + if case let .stickerPack(rhsStickerPack, rhsMedia) = rhs, lhsStickerPack == rhsStickerPack, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } + case let .savedGif(lhsMedia): + if case let .savedGif(rhsMedia) = rhs, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } + } + } + + public var partial: PartialMediaReference? { + switch self { + case .standalone: + return nil + case let .message(message, _): + return .message(message: message) + case let .webPage(webPage, _): + return .webPage(webPage: webPage) + case let .stickerPack(stickerPack, _): + return .stickerPack(stickerPack: stickerPack) + case .savedGif: + return .savedGif + } + } + + public func concrete(_ type: T.Type) -> MediaReference? { + switch self { + case let .standalone(media): + if let media = media as? T { + return .standalone(media: media) + } + case let .message(message, media): + if let media = media as? T { + return .message(message: message, media: media) + } + case let .webPage(webPage, media): + if let media = media as? T { + return .webPage(webPage: webPage, media: media) + } + case let .stickerPack(stickerPack, media): + if let media = media as? T { + return .stickerPack(stickerPack: stickerPack, media: media) + } + case let .savedGif(media): + if let media = media as? T { + return .savedGif(media: media) + } + } + return nil + } + + public var media: Media { + switch self { + case let .standalone(media): + return media + case let .message(_, media): + return media + case let .webPage(_, media): + return media + case let .stickerPack(_, media): + return media + case let .savedGif(media): + return media + } + } + + public func resourceReference(_ resource: MediaResource) -> MediaResourceReference { + return .media(media: self, resource: resource) + } +} + +public enum PartialMediaReference: Equatable { + private enum CodingCase: Int32 { + case message + case webPage + case stickerPack + case savedGif + } + + case message(message: MessageReference) + case webPage(webPage: WebpageReference) + case stickerPack(stickerPack: StickerPackReference) + case savedGif + + init?(decoder: PostboxDecoder) { + guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else { + return nil + } + switch caseId { + case .message: + let message = decoder.decodeObjectForKey("msg", decoder: { MessageReference(decoder: $0) }) as! MessageReference + self = .message(message: message) + case .webPage: + let webPage = decoder.decodeObjectForKey("wpg", decoder: { WebpageReference(decoder: $0) }) as! WebpageReference + self = .webPage(webPage: webPage) + case .stickerPack: + let stickerPack = decoder.decodeObjectForKey("spk", decoder: { StickerPackReference(decoder: $0) }) as! StickerPackReference + self = .stickerPack(stickerPack: stickerPack) + case .savedGif: + self = .savedGif + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .message(message): + encoder.encodeInt32(CodingCase.message.rawValue, forKey: "_r") + encoder.encodeObject(message, forKey: "msg") + case let .webPage(webPage): + encoder.encodeInt32(CodingCase.webPage.rawValue, forKey: "_r") + encoder.encodeObject(webPage, forKey: "wpg") + case let .stickerPack(stickerPack): + encoder.encodeInt32(CodingCase.stickerPack.rawValue, forKey: "_r") + encoder.encodeObject(stickerPack, forKey: "spk") + case .savedGif: + encoder.encodeInt32(CodingCase.savedGif.rawValue, forKey: "_r") + } + } + + func mediaReference(_ media: Media) -> AnyMediaReference { + switch self { + case let .message(message): + return .message(message: message, media: media) + case let .webPage(webPage): + return .webPage(webPage: webPage, media: media) + case let .stickerPack(stickerPack): + return .stickerPack(stickerPack: stickerPack, media: media) + case .savedGif: + return .savedGif(media: media) + } + } +} + +public enum MediaReference { + private enum CodingCase: Int32 { + case standalone + case message + case webPage + case stickerPack + case savedGif + } + + case standalone(media: T) + case message(message: MessageReference, media: T) + case webPage(webPage: WebpageReference, media: T) + case stickerPack(stickerPack: StickerPackReference, media: T) + case savedGif(media: T) + + init?(decoder: PostboxDecoder) { + guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else { + return nil + } + switch caseId { + case .standalone: + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + self = .standalone(media: media) + case .message: + let message = decoder.decodeObjectForKey("msg", decoder: { MessageReference(decoder: $0) }) as! MessageReference + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + self = .message(message: message, media: media) + case .webPage: + let webPage = decoder.decodeObjectForKey("wpg", decoder: { WebpageReference(decoder: $0) }) as! WebpageReference + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + self = .webPage(webPage: webPage, media: media) + case .stickerPack: + let stickerPack = decoder.decodeObjectForKey("spk", decoder: { StickerPackReference(decoder: $0) }) as! StickerPackReference + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + self = .stickerPack(stickerPack: stickerPack, media: media) + case .savedGif: + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + self = .savedGif(media: media) + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .standalone(media): + encoder.encodeInt32(CodingCase.standalone.rawValue, forKey: "_r") + encoder.encodeObject(media, forKey: "m") + case let .message(message, media): + encoder.encodeInt32(CodingCase.message.rawValue, forKey: "_r") + encoder.encodeObject(message, forKey: "msg") + encoder.encodeObject(media, forKey: "m") + case let .webPage(webPage, media): + encoder.encodeInt32(CodingCase.webPage.rawValue, forKey: "_r") + encoder.encodeObject(webPage, forKey: "wpg") + encoder.encodeObject(media, forKey: "m") + case let .stickerPack(stickerPack, media): + encoder.encodeInt32(CodingCase.stickerPack.rawValue, forKey: "_r") + encoder.encodeObject(stickerPack, forKey: "spk") + encoder.encodeObject(media, forKey: "m") + case let .savedGif(media): + encoder.encodeInt32(CodingCase.savedGif.rawValue, forKey: "_r") + encoder.encodeObject(media, forKey: "m") + } + } + + public var abstract: AnyMediaReference { + switch self { + case let .standalone(media): + return .standalone(media: media) + case let .message(message, media): + return .message(message: message, media: media) + case let .webPage(webPage, media): + return .webPage(webPage: webPage, media: media) + case let .stickerPack(stickerPack, media): + return .stickerPack(stickerPack: stickerPack, media: media) + case let .savedGif(media): + return .savedGif(media: media) + } + } + + public var partial: PartialMediaReference? { + return self.abstract.partial + } + + public var media: T { + switch self { + case let .standalone(media): + return media + case let .message(_, media): + return media + case let .webPage(_, media): + return media + case let .stickerPack(_, media): + return media + case let .savedGif(media): + return media + } + } + + public func resourceReference(_ resource: MediaResource) -> MediaResourceReference { + return .media(media: self.abstract, resource: resource) + } +} + +public typealias FileMediaReference = MediaReference +public typealias ImageMediaReference = MediaReference + +public enum MediaResourceReference: Equatable { + case media(media: AnyMediaReference, resource: MediaResource) + case standalone(resource: MediaResource) + case avatar(peer: PeerReference, resource: MediaResource) + case messageAuthorAvatar(message: MessageReference, resource: MediaResource) + case wallpaper(resource: MediaResource) + case stickerPackThumbnail(stickerPack: StickerPackReference, resource: MediaResource) + + public var resource: MediaResource { + switch self { + case let .media(_, resource): + return resource + case let .standalone(resource): + return resource + case let .avatar(_, resource): + return resource + case let .messageAuthorAvatar(_, resource): + return resource + case let .wallpaper(resource): + return resource + case let .stickerPackThumbnail(_, resource): + return resource + } + } + + public static func ==(lhs: MediaResourceReference, rhs: MediaResourceReference) -> Bool { + switch lhs { + case let .media(lhsMedia, lhsResource): + if case let .media(rhsMedia, rhsResource) = rhs, lhsMedia == rhsMedia, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + case let .standalone(lhsResource): + if case let .standalone(rhsResource) = rhs, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + case let .avatar(lhsPeer, lhsResource): + if case let .avatar(rhsPeer, rhsResource) = rhs, lhsPeer == rhsPeer, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + case let .messageAuthorAvatar(lhsMessage, lhsResource): + if case let .messageAuthorAvatar(rhsMessage, rhsResource) = rhs, lhsMessage == rhsMessage, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + case let .wallpaper(lhsResource): + if case let .wallpaper(rhsResource) = rhs, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + case let .stickerPackThumbnail(lhsStickerPack, lhsResource): + if case let .stickerPackThumbnail(rhsStickerPack, rhsResource) = rhs, lhsStickerPack == rhsStickerPack, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } + } + } +} + +extension MediaResourceReference { + var apiFileReference: Data? { + if let resource = self.resource as? TelegramCloudMediaResourceWithFileReference { + return resource.fileReference + } else { + return nil + } + } +} + +final class TelegramCloudMediaResourceFetchInfo: MediaResourceFetchInfo { + let reference: MediaResourceReference + let preferBackgroundReferenceRevalidation: Bool + let continueInBackground: Bool + + init(reference: MediaResourceReference, preferBackgroundReferenceRevalidation: Bool, continueInBackground: Bool) { + self.reference = reference + self.preferBackgroundReferenceRevalidation = preferBackgroundReferenceRevalidation + self.continueInBackground = continueInBackground + } +} + +public func fetchedMediaResource(postbox: Postbox, reference: MediaResourceReference, range: (Range, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { + return fetchedMediaResource(postbox: postbox, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground) +} + +public func fetchedMediaResource(postbox: Postbox, reference: MediaResourceReference, ranges: [(Range, MediaBoxFetchPriority)]?, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { + if let ranges = ranges { + let signals = ranges.map { (range, priority) -> Signal in + return postbox.mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground))) + } + return combineLatest(signals) + |> ignoreValues + |> map { _ -> FetchResourceSourceType in .local } + |> then(.single(.local)) + } else { + return postbox.mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground)), implNext: reportResultStatus) + } +} + +enum RevalidateMediaReferenceError { + case generic +} + +public func stickerPackFileReference(_ file: TelegramMediaFile) -> FileMediaReference { + for attribute in file.attributes { + if case let .Sticker(sticker) = attribute, let stickerPack = sticker.packReference { + return .stickerPack(stickerPack: stickerPack, media: file) + } + } + return .standalone(media: file) +} + +private func findMediaResource(media: Media, previousMedia: Media?, resource: MediaResource) -> TelegramMediaResource? { + if let image = media as? TelegramMediaImage { + for representation in image.representations { + if representation.resource.id.isEqual(to: resource.id) { + return representation.resource + } + } + if let legacyResource = resource as? CloudFileMediaResource { + for representation in image.representations { + if let updatedResource = representation.resource as? CloudPhotoSizeMediaResource { + if updatedResource.localId == legacyResource.localId && updatedResource.volumeId == legacyResource.volumeId { + return representation.resource + } + } + } + } + } else if let file = media as? TelegramMediaFile { + if file.resource.id.isEqual(to: resource.id) { + return file.resource + } else { + for representation in file.previewRepresentations { + if representation.resource.id.isEqual(to: resource.id) { + return representation.resource + } + } + if let legacyResource = resource as? CloudFileMediaResource { + for representation in file.previewRepresentations { + if let updatedResource = representation.resource as? CloudDocumentSizeMediaResource { + if updatedResource.localId == legacyResource.localId && updatedResource.volumeId == legacyResource.volumeId { + return representation.resource + } + } + } + } + } + } else if let webPage = media as? TelegramMediaWebpage, case let .Loaded(content) = webPage.content { + if let image = content.image, let result = findMediaResource(media: image, previousMedia: previousMedia, resource: resource) { + return result + } + if let file = content.file, let result = findMediaResource(media: file, previousMedia: previousMedia, resource: resource) { + return result + } + if let instantPage = content.instantPage { + for pageMedia in instantPage.media.values { + if let result = findMediaResource(media: pageMedia, previousMedia: previousMedia, resource: resource) { + return result + } + } + } + } else if let game = media as? TelegramMediaGame { + if let image = game.image, let result = findMediaResource(media: image, previousMedia: previousMedia, resource: resource) { + return result + } + if let file = game.file, let result = findMediaResource(media: file, previousMedia: previousMedia, resource: resource) { + return result + } + } else if let action = media as? TelegramMediaAction { + switch action.action { + case let .photoUpdated(image): + if let image = image, let result = findMediaResource(media: image, previousMedia: previousMedia, resource: resource) { + return result + } + default: + break + } + } + return nil +} + +private func findUpdatedMediaResource(media: Media, previousMedia: Media?, resource: MediaResource) -> TelegramMediaResource? { + if let foundResource = findMediaResource(media: media, previousMedia: previousMedia, resource: resource) { + return foundResource + } else { + return nil + } +} + +private enum MediaReferenceRevalidationKey: Hashable { + case message(message: MessageReference) + case webPage(webPage: WebpageReference) + case stickerPack(stickerPack: StickerPackReference) + case savedGifs + case peer(peer: PeerReference) + case wallpapers +} + +private final class MediaReferenceRevalidationItemContext { + let subscribers = Bag<(Any) -> Void>() + let disposable: Disposable + + init(disposable: Disposable) { + self.disposable = disposable + } + + deinit { + self.disposable.dispose() + } + + var isEmpty: Bool { + return self.subscribers.isEmpty + } + + func addSubscriber(_ f: @escaping (Any) -> Void) -> Int { + return self.subscribers.add(f) + } + + func removeSubscriber(_ index: Int) { + self.subscribers.remove(index) + } +} + +private struct MediaReferenceRevalidationKeyAndPlacement: Hashable { + let key: MediaReferenceRevalidationKey + let background: Bool +} + +private final class MediaReferenceRevalidationContextImpl { + let queue: Queue + + var itemContexts: [MediaReferenceRevalidationKeyAndPlacement: MediaReferenceRevalidationItemContext] = [:] + + init(queue: Queue) { + self.queue = queue + } + + func genericItem(key: MediaReferenceRevalidationKey, background: Bool, request: @escaping (@escaping (Any) -> Void, @escaping (RevalidateMediaReferenceError) -> Void) -> Disposable, _ f: @escaping (Any) -> Void) -> Disposable { + let queue = self.queue + + let itemKey = MediaReferenceRevalidationKeyAndPlacement(key: key, background: background) + + let context: MediaReferenceRevalidationItemContext + if let current = self.itemContexts[itemKey] { + context = current + } else { + let disposable = MetaDisposable() + context = MediaReferenceRevalidationItemContext(disposable: disposable) + self.itemContexts[itemKey] = context + disposable.set(request({ [weak self] result in + queue.async { + guard let strongSelf = self else { + return + } + if let current = strongSelf.itemContexts[itemKey], current === context { + strongSelf.itemContexts.removeValue(forKey: itemKey) + for subscriber in current.subscribers.copyItems() { + subscriber(result) + } + } + } + }, { [weak self] _ in + /*queue.async { + guard let strongSelf = self else { + return + } + }*/ + })) + } + + let index = context.addSubscriber(f) + + return ActionDisposable { [weak self, weak context] in + queue.async { + guard let strongSelf = self else { + return + } + if let current = strongSelf.itemContexts[itemKey], current === context { + current.removeSubscriber(index) + if current.isEmpty { + current.disposable.dispose() + strongSelf.itemContexts.removeValue(forKey: itemKey) + } + } + } + } + } +} + +final class MediaReferenceRevalidationContext { + private let queue: Queue + private let impl: QueueLocalObject + + init() { + self.queue = Queue() + let queue = self.queue + self.impl = QueueLocalObject(queue: self.queue, generate: { + return MediaReferenceRevalidationContextImpl(queue: queue) + }) + } + + private func genericItem(key: MediaReferenceRevalidationKey, background: Bool, request: @escaping (@escaping (Any) -> Void, @escaping (RevalidateMediaReferenceError) -> Void) -> Disposable) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.genericItem(key: key, background: background, request: request, { result in + subscriber.putNext(result) + subscriber.putCompletion() + })) + } + return disposable + } + } + + func message(postbox: Postbox, network: Network, background: Bool, message: MessageReference) -> Signal { + return self.genericItem(key: .message(message: message), background: background, request: { next, error in + let source: Signal + if background { + source = network.background() + |> map(FetchMessageHistoryHoleSource.download) + } else { + source = .single(.network(network)) + } + let signal = source + |> mapToSignal { source -> Signal in + return fetchRemoteMessage(postbox: postbox, source: source, message: message) + } + return signal.start(next: { value in + if let value = value { + next(value) + } else { + error(.generic) + } + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal in + if let next = next as? Message { + return .single(next) + } else { + return .fail(.generic) + } + } + } + + func stickerPack(postbox: Postbox, network: Network, background: Bool, stickerPack: StickerPackReference) -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), RevalidateMediaReferenceError> { + return self.genericItem(key: .stickerPack(stickerPack: stickerPack), background: background, request: { next, error in + return (updatedRemoteStickerPack(postbox: postbox, network: network, reference: stickerPack) + |> mapError { _ -> RevalidateMediaReferenceError in + return .generic + }).start(next: { value in + if let value = value { + next(value) + } else { + error(.generic) + } + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), RevalidateMediaReferenceError> in + if let next = next as? (StickerPackCollectionInfo, [ItemCollectionItem]) { + return .single(next) + } else { + return .fail(.generic) + } + } + } + + func webPage(postbox: Postbox, network: Network, background: Bool, webPage: WebpageReference) -> Signal { + return self.genericItem(key: .webPage(webPage: webPage), background: background, request: { next, error in + return (updatedRemoteWebpage(postbox: postbox, network: network, webPage: webPage) + |> mapError { _ -> RevalidateMediaReferenceError in + return .generic + }).start(next: { value in + if let value = value { + next(value) + } else { + error(.generic) + } + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal in + if let next = next as? TelegramMediaWebpage { + return .single(next) + } else { + return .fail(.generic) + } + } + } + + func savedGifs(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> { + return self.genericItem(key: .savedGifs, background: background, request: { next, error in + let loadRecentGifs: Signal<[TelegramMediaFile], NoError> = postbox.transaction { transaction -> [TelegramMediaFile] in + return transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs).compactMap({ item -> TelegramMediaFile? in + if let contents = item.contents as? RecentMediaItem, let file = contents.media as? TelegramMediaFile { + return file + } + return nil + }) + } + return (managedRecentGifs(postbox: postbox, network: network, forceFetch: true) + |> mapToSignal { _ -> Signal<[TelegramMediaFile], NoError> in + return .complete() + } + |> then(loadRecentGifs) + |> introduceError(RevalidateMediaReferenceError.self)).start(next: { value in + next(value) + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> in + if let next = next as? [TelegramMediaFile] { + return .single(next) + } else { + return .fail(.generic) + } + } + } + + func peer(postbox: Postbox, network: Network, background: Bool, peer: PeerReference) -> Signal { + return self.genericItem(key: .peer(peer: peer), background: background, request: { next, error in + return (updatedRemotePeer(postbox: postbox, network: network, peer: peer) + |> mapError { _ -> RevalidateMediaReferenceError in + return .generic + }).start(next: { value in + next(value) + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal in + if let next = next as? Peer { + return .single(next) + } else { + return .fail(.generic) + } + } + } + + func wallpapers(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramWallpaper], RevalidateMediaReferenceError> { + return self.genericItem(key: .wallpapers, background: background, request: { next, error in + return (telegramWallpapers(postbox: postbox, network: network, forceUpdate: true) + |> last + |> mapError { _ -> RevalidateMediaReferenceError in + return .generic + }).start(next: { value in + if let value = value { + next(value) + } else { + error(.generic) + } + }, error: { _ in + error(.generic) + }) + }) |> mapToSignal { next -> Signal<[TelegramWallpaper], RevalidateMediaReferenceError> in + if let next = next as? [TelegramWallpaper] { + return .single(next) + } else { + return .fail(.generic) + } + } + } +} + +struct RevalidatedMediaResource { + let updatedResource: TelegramMediaResource + let updatedReference: MediaResourceReference? +} + +func revalidateMediaResourceReference(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo, resource: MediaResource) -> Signal { + var updatedReference = info.reference + if case let .media(media, resource) = updatedReference { + if case let .message(_, mediaValue) = media { + if let file = mediaValue as? TelegramMediaFile { + if let partialReference = file.partialReference { + updatedReference = partialReference.mediaReference(media.media).resourceReference(resource) + } + if file.isSticker { + var stickerPackReference: StickerPackReference? + for attribute in file.attributes { + if case let .Sticker(sticker) = attribute { + if let packReference = sticker.packReference { + stickerPackReference = packReference + } + } + } + if let stickerPackReference = stickerPackReference { + updatedReference = .media(media: .stickerPack(stickerPack: stickerPackReference, media: mediaValue), resource: resource) + } + } + } else if let image = mediaValue as? TelegramMediaImage { + if let partialReference = image.partialReference { + updatedReference = partialReference.mediaReference(media.media).resourceReference(resource) + } + } + } + } + + switch updatedReference { + case let .media(media, _): + switch media { + case let .message(message, previousMedia): + return revalidationContext.message(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, message: message) + |> mapToSignal { message -> Signal in + for media in message.media { + if let updatedResource = findUpdatedMediaResource(media: media, previousMedia: previousMedia, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + return .fail(.generic) + } + case let .stickerPack(stickerPack, media): + return revalidationContext.stickerPack(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, stickerPack: stickerPack) + |> mapToSignal { result -> Signal in + for item in result.1 { + if let item = item as? StickerPackItem { + if media.id != nil && item.file.id == media.id { + if let updatedResource = findUpdatedMediaResource(media: item.file, previousMedia: media, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + } + } + return .fail(.generic) + } + case let .webPage(webPage, previousMedia): + return revalidationContext.webPage(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, webPage: webPage) + |> mapToSignal { result -> Signal in + if let updatedResource = findUpdatedMediaResource(media: result, previousMedia: previousMedia, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + return .fail(.generic) + } + case let .savedGif(media): + return revalidationContext.savedGifs(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation) + |> mapToSignal { result -> Signal in + for file in result { + if media.id != nil && file.id == media.id { + if let updatedResource = findUpdatedMediaResource(media: file, previousMedia: media, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + } + return .fail(.generic) + } + case let .standalone(media): + if let file = media as? TelegramMediaFile { + for attribute in file.attributes { + if case let .Sticker(sticker) = attribute, let stickerPack = sticker.packReference { + return revalidationContext.stickerPack(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, stickerPack: stickerPack) + |> mapToSignal { result -> Signal in + for item in result.1 { + if let item = item as? StickerPackItem { + if media.id != nil && item.file.id == media.id { + if let updatedResource = findUpdatedMediaResource(media: item.file, previousMedia: media, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + } + } + return .fail(.generic) + } + } + } + } + return .fail(.generic) + } + case let .avatar(peer, _): + return revalidationContext.peer(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, peer: peer) + |> mapToSignal { updatedPeer -> Signal in + for representation in updatedPeer.profileImageRepresentations { + if representation.resource.id.isEqual(to: resource.id) { + return .single(RevalidatedMediaResource(updatedResource: representation.resource, updatedReference: nil)) + } + } + if let legacyResource = resource as? CloudFileMediaResource { + for representation in updatedPeer.profileImageRepresentations { + if let updatedResource = representation.resource as? CloudPeerPhotoSizeMediaResource { + if updatedResource.localId == legacyResource.localId && updatedResource.volumeId == legacyResource.volumeId { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + } + } + return .fail(.generic) + } + case let .messageAuthorAvatar(message, _): + return revalidationContext.message(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, message: message) + |> mapToSignal { updatedMessage -> Signal in + guard let author = updatedMessage.author, let authorReference = PeerReference(author) else { + return .fail(.generic) + } + for representation in author.profileImageRepresentations { + if representation.resource.id.isEqual(to: resource.id) { + return .single(RevalidatedMediaResource(updatedResource: representation.resource, updatedReference: .avatar(peer: authorReference, resource: representation.resource))) + } + } + if let legacyResource = resource as? CloudFileMediaResource { + for representation in author.profileImageRepresentations { + if let updatedResource = representation.resource as? CloudPeerPhotoSizeMediaResource { + if updatedResource.localId == legacyResource.localId && updatedResource.volumeId == legacyResource.volumeId { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: .avatar(peer: authorReference, resource: updatedResource))) + } + } + } + } + return .fail(.generic) + } + case .wallpaper: + return revalidationContext.wallpapers(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation) + |> mapToSignal { wallpapers -> Signal in + for wallpaper in wallpapers { + switch wallpaper { + case let .image(representations, _): + for representation in representations { + if representation.resource.id.isEqual(to: resource.id) { + return .single(RevalidatedMediaResource(updatedResource: representation.resource, updatedReference: nil)) + } + } + case let .file(_, _, _, _, _, _, _, file, _): + if let updatedResource = findUpdatedMediaResource(media: file, previousMedia: nil, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + default: + break + } + } + return .fail(.generic) + } + case let .stickerPackThumbnail(packReference, resource): + return revalidationContext.stickerPack(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, stickerPack: packReference) + |> mapToSignal { result -> Signal in + if let thumbnail = result.0.thumbnail { + if thumbnail.resource.id.isEqual(to: resource.id) { + return .single(RevalidatedMediaResource(updatedResource: thumbnail.resource, updatedReference: nil)) + } + if let legacyResource = resource as? CloudFileMediaResource { + if let updatedResource = thumbnail.resource as? CloudStickerPackThumbnailMediaResource { + if updatedResource.localId == legacyResource.localId && updatedResource.volumeId == legacyResource.volumeId { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + } + } + } + return .fail(.generic) + } + case .standalone: + return .fail(.generic) + } +} diff --git a/submodules/TelegramCore/TelegramCore/FindChannelById.swift b/submodules/TelegramCore/TelegramCore/FindChannelById.swift new file mode 100644 index 0000000000..0d9b8bd20e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/FindChannelById.swift @@ -0,0 +1,41 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public func findChannelById(postbox: Postbox, network: Network, channelId: Int32) -> Signal { + return network.request(Api.functions.channels.getChannels(id: [.inputChannel(channelId: channelId, accessHash: 0)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .single(nil) + } + let chats: [Api.Chat] + switch result { + case let .chats(apiChats): + chats = apiChats + case let .chatsSlice(_, apiChats): + chats = apiChats + } + guard let chat = chats.first else { + return .single(nil) + } + guard let peer = parseTelegramGroupOrChannel(chat: chat) else { + return .single(nil) + } + + return postbox.transaction { transaction -> Peer? in + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in + return updated + }) + return peer + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ForwardGame.swift b/submodules/TelegramCore/TelegramCore/ForwardGame.swift new file mode 100644 index 0000000000..b4d09b4e95 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ForwardGame.swift @@ -0,0 +1,27 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func forwardGameWithScore(account: Account, messageId: MessageId, to peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let message = transaction.getMessage(messageId), let fromPeer = transaction.getPeer(messageId.peerId), let fromInputPeer = apiInputPeer(fromPeer), let toPeer = transaction.getPeer(peerId), let toInputPeer = apiInputPeer(toPeer) { + return account.network.request(Api.functions.messages.forwardMessages(flags: 1 << 8, fromPeer: fromInputPeer, id: [messageId.id], randomId: [arc4random64()], toPeer: toInputPeer)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + } + return .complete() + } + } + return .complete() + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ForwardSourceInfoAttribute.swift b/submodules/TelegramCore/TelegramCore/ForwardSourceInfoAttribute.swift new file mode 100644 index 0000000000..aee4c48459 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ForwardSourceInfoAttribute.swift @@ -0,0 +1,24 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ForwardSourceInfoAttribute: MessageAttribute { + public let messageId: MessageId + + init(messageId: MessageId) { + self.messageId = messageId + } + + required public init(decoder: PostboxDecoder) { + self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: decoder.decodeInt32ForKey("n", orElse: 0), id: decoder.decodeInt32ForKey("i", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") + encoder.encodeInt32(self.messageId.namespace, forKey: "n") + encoder.encodeInt32(self.messageId.id, forKey: "i") + } +} diff --git a/submodules/TelegramCore/TelegramCore/GlobalNotificationSettings.swift b/submodules/TelegramCore/TelegramCore/GlobalNotificationSettings.swift new file mode 100644 index 0000000000..b0f35b538b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GlobalNotificationSettings.swift @@ -0,0 +1,125 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct MessageNotificationSettings: PostboxCoding, Equatable { + public var enabled: Bool + public var displayPreviews: Bool + public var sound: PeerMessageSound + + public static var defaultSettings: MessageNotificationSettings { + return MessageNotificationSettings(enabled: true, displayPreviews: true, sound: .bundledModern(id: 0)) + } + + public init(enabled: Bool, displayPreviews: Bool, sound: PeerMessageSound) { + self.enabled = enabled + self.displayPreviews = displayPreviews + self.sound = sound + } + + public init(decoder: PostboxDecoder) { + self.enabled = decoder.decodeInt32ForKey("e", orElse: 0) != 0 + self.displayPreviews = decoder.decodeInt32ForKey("p", orElse: 0) != 0 + self.sound = PeerMessageSound.decodeInline(decoder) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "e") + encoder.encodeInt32(self.displayPreviews ? 1 : 0, forKey: "p") + self.sound.encodeInline(encoder) + } +} + +public struct GlobalNotificationSettingsSet: PostboxCoding, Equatable { + public var privateChats: MessageNotificationSettings + public var groupChats: MessageNotificationSettings + public var channels: MessageNotificationSettings + public var contactsJoined: Bool + + public static var defaultSettings: GlobalNotificationSettingsSet { + return GlobalNotificationSettingsSet(privateChats: MessageNotificationSettings.defaultSettings, groupChats: .defaultSettings, channels: .defaultSettings, contactsJoined: true) + } + + public init(privateChats: MessageNotificationSettings, groupChats: MessageNotificationSettings, channels: MessageNotificationSettings, contactsJoined: Bool) { + self.privateChats = privateChats + self.groupChats = groupChats + self.channels = channels + self.contactsJoined = contactsJoined + } + + public init(decoder: PostboxDecoder) { + self.privateChats = decoder.decodeObjectForKey("p", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings + self.groupChats = decoder.decodeObjectForKey("g", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings + self.channels = (decoder.decodeObjectForKey("c", decoder: { MessageNotificationSettings(decoder: $0) }) as? MessageNotificationSettings) ?? MessageNotificationSettings.defaultSettings + self.contactsJoined = decoder.decodeInt32ForKey("contactsJoined", orElse: 1) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.privateChats, forKey: "p") + encoder.encodeObject(self.groupChats, forKey: "g") + encoder.encodeObject(self.channels, forKey: "c") + encoder.encodeInt32(self.contactsJoined ? 1 : 0, forKey: "contactsJoined") + } +} + +public struct GlobalNotificationSettings: PreferencesEntry, Equatable { + var toBeSynchronized: GlobalNotificationSettingsSet? + var remote: GlobalNotificationSettingsSet + + public static var defaultSettings: GlobalNotificationSettings = GlobalNotificationSettings(toBeSynchronized: nil, remote: GlobalNotificationSettingsSet.defaultSettings) + + public var effective: GlobalNotificationSettingsSet { + if let toBeSynchronized = self.toBeSynchronized { + return toBeSynchronized + } else { + return self.remote + } + } + + init(toBeSynchronized: GlobalNotificationSettingsSet?, remote: GlobalNotificationSettingsSet) { + self.toBeSynchronized = toBeSynchronized + self.remote = remote + } + + public init(decoder: PostboxDecoder) { + self.toBeSynchronized = decoder.decodeObjectForKey("s", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as? GlobalNotificationSettingsSet + self.remote = decoder.decodeObjectForKey("r", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as! GlobalNotificationSettingsSet + } + + public func encode(_ encoder: PostboxEncoder) { + if let toBeSynchronized = self.toBeSynchronized { + encoder.encodeObject(toBeSynchronized, forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + encoder.encodeObject(self.remote, forKey: "r") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? GlobalNotificationSettings { + return self == to + } else { + return false + } + } +} + +extension MessageNotificationSettings { + init(apiSettings: Api.PeerNotifySettings) { + switch apiSettings { + case .peerNotifySettingsEmpty: + self = .defaultSettings + case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + self = MessageNotificationSettings(enabled: muteUntil == 0, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? "2")) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/GlobalTelegramCoreConfiguration.swift b/submodules/TelegramCore/TelegramCore/GlobalTelegramCoreConfiguration.swift new file mode 100644 index 0000000000..7cf05d8aa9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GlobalTelegramCoreConfiguration.swift @@ -0,0 +1,5 @@ +import Foundation + +public final class GlobalTelegramCoreConfiguration { + public static var readMessages: Bool = true +} diff --git a/submodules/TelegramCore/TelegramCore/GrantSecureIdAccess.swift b/submodules/TelegramCore/TelegramCore/GrantSecureIdAccess.swift new file mode 100644 index 0000000000..a04eb8f92b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GrantSecureIdAccess.swift @@ -0,0 +1,350 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +func apiSecureValueType(value: SecureIdValue) -> Api.SecureValueType { + let type: Api.SecureValueType + switch value { + case .personalDetails: + type = .secureValueTypePersonalDetails + case .passport: + type = .secureValueTypePassport + case .internalPassport: + type = .secureValueTypeInternalPassport + case .driversLicense: + type = .secureValueTypeDriverLicense + case .idCard: + type = .secureValueTypeIdentityCard + case .address: + type = .secureValueTypeAddress + case .passportRegistration: + type = .secureValueTypePassportRegistration + case .temporaryRegistration: + type = .secureValueTypeTemporaryRegistration + case .bankStatement: + type = .secureValueTypeBankStatement + case .utilityBill: + type = .secureValueTypeUtilityBill + case .rentalAgreement: + type = .secureValueTypeRentalAgreement + case .phone: + type = .secureValueTypePhone + case .email: + type = .secureValueTypeEmail + } + return type +} + +func apiSecureValueType(key: SecureIdValueKey) -> Api.SecureValueType { + let type: Api.SecureValueType + switch key { + case .personalDetails: + type = .secureValueTypePersonalDetails + case .passport: + type = .secureValueTypePassport + case .internalPassport: + type = .secureValueTypeInternalPassport + case .driversLicense: + type = .secureValueTypeDriverLicense + case .idCard: + type = .secureValueTypeIdentityCard + case .address: + type = .secureValueTypeAddress + case .passportRegistration: + type = .secureValueTypePassportRegistration + case .temporaryRegistration: + type = .secureValueTypeTemporaryRegistration + case .bankStatement: + type = .secureValueTypeBankStatement + case .utilityBill: + type = .secureValueTypeUtilityBill + case .rentalAgreement: + type = .secureValueTypeRentalAgreement + case .phone: + type = .secureValueTypePhone + case .email: + type = .secureValueTypeEmail + } + return type +} + +extension SecureIdValueKey { + init(apiType: Api.SecureValueType) { + switch apiType { + case .secureValueTypePersonalDetails: + self = .personalDetails + case .secureValueTypePassport: + self = .passport + case .secureValueTypeDriverLicense: + self = .driversLicense + case .secureValueTypeIdentityCard: + self = .idCard + case .secureValueTypeInternalPassport: + self = .internalPassport + case .secureValueTypeAddress: + self = .address + case .secureValueTypeUtilityBill: + self = .utilityBill + case .secureValueTypeBankStatement: + self = .bankStatement + case .secureValueTypeRentalAgreement: + self = .rentalAgreement + case .secureValueTypePassportRegistration: + self = .passportRegistration + case .secureValueTypeTemporaryRegistration: + self = .temporaryRegistration + case .secureValueTypePhone: + self = .phone + case .secureValueTypeEmail: + self = .email + } + } +} + +private func credentialsValueTypeName(value: SecureIdValue) -> String { + switch value { + case .personalDetails: + return "personal_details" + case .passport: + return "passport" + case .internalPassport: + return "internal_passport" + case .driversLicense: + return "driver_license" + case .idCard: + return "identity_card" + case .address: + return "address" + case .passportRegistration: + return "passport_registration" + case .temporaryRegistration: + return "temporary_registration" + case .bankStatement: + return "bank_statement" + case .utilityBill: + return "utility_bill" + case .rentalAgreement: + return "rental_agreement" + case .phone: + return "phone" + case .email: + return "email" + } +} + +private func generateCredentials(values: [SecureIdValueWithContext], requestedFields: [SecureIdRequestedFormField], opaquePayload: Data, opaqueNonce: Data) -> Data? { + var secureData: [String: Any] = [:] + + let requestedFieldValues = requestedFields.flatMap({ field -> [SecureIdRequestedFormFieldValue] in + switch field { + case let .just(value): + return [value] + case let .oneOf(values): + return values + } + }) + + let valueTypeToSkipFields: [SecureIdValueKey: (SecureIdRequestedFormFieldValue) -> (needsSelfie: Bool, needsTranslations: Bool)?] = [ + .idCard: { + if case let .idCard(selfie, translations) = $0 { + return (selfie, translations) + } else { + return nil + } + }, + .passport: { + if case let .passport(selfie, translations) = $0 { + return (selfie, translations) + } else { + return nil + } + }, + .driversLicense: { + if case let .driversLicense(selfie, translations) = $0 { + return (selfie, translations) + } else { + return nil + } + }, + .internalPassport: { + if case let .internalPassport(selfie, translations) = $0 { + return (selfie, translations) + } else { + return nil + } + }, + .passportRegistration: { + if case let .passportRegistration(translations) = $0 { + return (false, translations) + } else { + return nil + } + }, + .temporaryRegistration: { + if case let .temporaryRegistration(translations) = $0 { + return (false, translations) + } else { + return nil + } + }, + .utilityBill: { + if case let .utilityBill(translations) = $0 { + return (false, translations) + } else { + return nil + } + }, + .bankStatement: { + if case let .bankStatement(translations) = $0 { + return (false, translations) + } else { + return nil + } + }, + .rentalAgreement: { + if case let .rentalAgreement(translations) = $0 { + return (false, translations) + } else { + return nil + } + } + ] + + + for value in values { + var skipSelfie = false + var skipTranslations = false + if let skipFilter = valueTypeToSkipFields[value.value.key] { + inner: for field in requestedFieldValues { + if let result = skipFilter(field) { + skipSelfie = !result.needsSelfie + skipTranslations = !result.needsTranslations + break inner + } + } + } + + var valueDict: [String: Any] = [:] + if let encryptedMetadata = value.encryptedMetadata { + valueDict["data"] = [ + "data_hash": encryptedMetadata.valueDataHash.base64EncodedString(), + "secret": encryptedMetadata.decryptedSecret.base64EncodedString() + ] as [String: Any] + } + + if !value.files.isEmpty { + valueDict["files"] = value.files.map { file -> [String: Any] in + return [ + "file_hash": file.hash.base64EncodedString(), + "secret": file.secret.base64EncodedString() + ] + } + } + + if !skipTranslations && !value.translations.isEmpty { + valueDict["translation"] = value.translations.map { file -> [String: Any] in + return [ + "file_hash": file.hash.base64EncodedString(), + "secret": file.secret.base64EncodedString() + ] + } + } + + if !skipSelfie, let selfie = value.selfie { + valueDict["selfie"] = [ + "file_hash": selfie.hash.base64EncodedString(), + "secret": selfie.secret.base64EncodedString() + ] as [String: Any] + } + if let frontside = value.frontSide { + valueDict["front_side"] = [ + "file_hash": frontside.hash.base64EncodedString(), + "secret": frontside.secret.base64EncodedString() + ] as [String: Any] + } + if let backside = value.backSide { + valueDict["reverse_side"] = [ + "file_hash": backside.hash.base64EncodedString(), + "secret": backside.secret.base64EncodedString() + ] as [String: Any] + } + if !valueDict.isEmpty { + secureData[credentialsValueTypeName(value: value.value)] = valueDict + } + } + + var dict: [String: Any] = [:] + dict["secure_data"] = secureData + + if !opaquePayload.isEmpty, let opaquePayload = String(data: opaquePayload, encoding: .utf8) { + dict["payload"] = opaquePayload + } + + if !opaqueNonce.isEmpty, let opaqueNonce = String(data: opaqueNonce, encoding: .utf8) { + dict["nonce"] = opaqueNonce + } + + guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else { + return nil + } + + return data +} + +private func encryptedCredentialsData(data: Data, secretData: Data) -> (data: Data, hash: Data)? { + let paddedData = paddedSecureIdData(data) + let hash = sha256Digest(paddedData) + let secretHash = sha512Digest(secretData + hash) + let key = secretHash.subdata(in: 0 ..< 32) + let iv = secretHash.subdata(in: 32 ..< (32 + 16)) + guard let encryptedData = encryptSecureData(key: key, iv: iv, data: paddedData, decrypt: false) else { + return nil + } + return (encryptedData, hash) +} + +public enum GrantSecureIdAccessError { + case generic +} + +public func grantSecureIdAccess(network: Network, peerId: PeerId, publicKey: String, scope: String, opaquePayload: Data, opaqueNonce: Data, values: [SecureIdValueWithContext], requestedFields: [SecureIdRequestedFormField]) -> Signal { + guard peerId.namespace == Namespaces.Peer.CloudUser else { + return .fail(.generic) + } + guard let credentialsSecretData = generateSecureSecretData() else { + return .fail(.generic) + } + guard let credentialsData = generateCredentials(values: values, requestedFields: requestedFields, opaquePayload: opaquePayload, opaqueNonce: opaqueNonce) else { + return .fail(.generic) + } + guard let (encryptedCredentialsData, decryptedCredentialsHash) = encryptedCredentialsData(data: credentialsData, secretData: credentialsSecretData) else { + return .fail(.generic) + } + guard let encryptedSecretData = MTRsaEncryptPKCS1OAEP(publicKey, credentialsSecretData) else { + return .fail(.generic) + } + + var valueHashes: [Api.SecureValueHash] = [] + for value in values { + valueHashes.append(.secureValueHash(type: apiSecureValueType(value: value.value), hash: Buffer(data: value.opaqueHash))) + } + + return network.request(Api.functions.account.acceptAuthorization(botId: peerId.id, scope: scope, publicKey: publicKey, valueHashes: valueHashes, credentials: .secureCredentialsEncrypted(data: Buffer(data: encryptedCredentialsData), hash: Buffer(data: decryptedCredentialsHash), secret: Buffer(data: encryptedSecretData)))) + |> mapError { error -> GrantSecureIdAccessError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/GroupFeedPeers.swift b/submodules/TelegramCore/TelegramCore/GroupFeedPeers.swift new file mode 100644 index 0000000000..b8bc9f4212 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GroupFeedPeers.swift @@ -0,0 +1,52 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func availableGroupFeedPeers(postbox: Postbox, network: Network, groupId: PeerGroupId) -> Signal<[(Peer, Bool)], NoError> { + /*feed*/ + return .single([]) + /*return network.request(Api.functions.channels.getFeedSources(flags: 0, feedId: groupId.rawValue, hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal<[(Peer, Bool)], NoError> in + return postbox.transaction { transaction -> [(Peer, Bool)] in + switch result { + case .feedSourcesNotModified: + return [] + case let .feedSources(_, newlyJoinedFeed, feeds, chats, users): + var includedPeerIds = Set() + var excludedPeerIds = Set() + for feedsInfo in feeds { + switch feedsInfo { + case let .feedBroadcasts(feedId, channels): + if feedId == groupId.rawValue { + for id in channels { + includedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) + } + } + case let .feedBroadcastsUngrouped(channels): + for id in channels { + excludedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) + } + } + } + var peers: [(Peer, Bool)] = [] + for peerId in includedPeerIds { + if let peer = transaction.getPeer(peerId) { + peers.append((peer, true)) + } + } + for peerId in excludedPeerIds { + if let peer = transaction.getPeer(peerId) { + peers.append((peer, false)) + } + } + return peers + } + } + }*/ +} diff --git a/submodules/TelegramCore/TelegramCore/GroupReturnAndLeft.swift b/submodules/TelegramCore/TelegramCore/GroupReturnAndLeft.swift new file mode 100644 index 0000000000..3a7bd2d1f4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GroupReturnAndLeft.swift @@ -0,0 +1,50 @@ + +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + + +public func returnGroup(account: Account, peerId: PeerId) -> Signal { + return account.postbox.loadedPeerWithId(account.peerId) + |> take(1) + |> mapToSignal { peer -> Signal in + if let inputUser = apiInputUser(peer) { + return account.network.request(Api.functions.messages.addChatUser(chatId: peerId.id, userId: inputUser, fwdLimit: 50)) + |> retryRequest + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + return .complete() + } + } else { + return .complete() + } + } +} + +public func leftGroup(account: Account, peerId: PeerId) -> Signal { + return account.postbox.loadedPeerWithId(account.peerId) + |> take(1) + |> mapToSignal { peer -> Signal in + if let inputUser = apiInputUser(peer) { + return account.network.request(Api.functions.messages .deleteChatUser(chatId: peerId.id, userId: inputUser)) + |> retryRequest + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + return .complete() + } + } else { + return .complete() + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/GroupsInCommon.swift b/submodules/TelegramCore/TelegramCore/GroupsInCommon.swift new file mode 100644 index 0000000000..3e18dfedb1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/GroupsInCommon.swift @@ -0,0 +1,41 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[PeerId], NoError> { + return account.postbox.transaction { transaction -> Signal<[PeerId], NoError> in + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + return account.network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: 0, limit: 100)) + |> retryRequest + |> mapToSignal { result -> Signal<[PeerId], NoError> in + let chats: [Api.Chat] + switch result { + case let .chats(chats: apiChats): + chats = apiChats + case let .chatsSlice(count: _, chats: apiChats): + chats = apiChats + } + + return account.postbox.transaction { transaction -> [PeerId] in + var peers:[Peer] = [] + for chat in chats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + peers.append(peer) + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer? in + return updated + }) + return peers.map {$0.id} + } + } + } else { + return .single([]) + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/HistoryViewChannelStateValidation.swift b/submodules/TelegramCore/TelegramCore/HistoryViewChannelStateValidation.swift new file mode 100644 index 0000000000..847fb10b3a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/HistoryViewChannelStateValidation.swift @@ -0,0 +1,608 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class HistoryStateValidationBatch { + private let disposable: Disposable + let invalidatedState: HistoryState + + var cancelledMessageIds = Set() + + init(disposable: Disposable, invalidatedState: HistoryState) { + self.disposable = disposable + self.invalidatedState = invalidatedState + } + + deinit { + disposable.dispose() + } +} + +private final class HistoryStateValidationContext { + var batchReferences: [MessageId: HistoryStateValidationBatch] = [:] +} + +private enum HistoryState { + case channel(PeerId, ChannelState) + //case group(PeerGroupId, TelegramPeerGroupState) + + var hasInvalidationIndex: Bool { + switch self { + case let .channel(_, state): + return state.invalidatedPts != nil + /*case let .group(_, state): + return state.invalidatedStateIndex != nil*/ + } + } + + func isMessageValid(_ message: Message) -> Bool { + switch self { + case let .channel(_, state): + if let invalidatedPts = state.invalidatedPts { + var messagePts: Int32? + inner: for attribute in message.attributes { + if let attribute = attribute as? ChannelMessageStateVersionAttribute { + messagePts = attribute.pts + break inner + } + } + var requiresValidation = false + if let messagePts = messagePts { + if messagePts < invalidatedPts { + requiresValidation = true + } + } else { + requiresValidation = true + } + + return !requiresValidation + } else { + return true + } + /*case let .group(_, state): + if let invalidatedStateIndex = state.invalidatedStateIndex { + var messageStateIndex: Int32? + inner: for attribute in message.attributes { + if let attribute = attribute as? PeerGroupMessageStateVersionAttribute { + messageStateIndex = attribute.stateIndex + break inner + } + } + var requiresValidation = false + if let messageStateIndex = messageStateIndex { + if messageStateIndex < invalidatedStateIndex { + requiresValidation = true + } + } else { + requiresValidation = true + } + return !requiresValidation + } else { + return true + }*/ + } + } + + func matchesPeerId(_ peerId: PeerId) -> Bool { + switch self { + case let .channel(statePeerId, state): + return statePeerId == peerId + /*case .group: + return true*/ + } + } +} + +private func slicedForValidationMessages(_ messages: [MessageId]) -> [[MessageId]] { + let block = 64 + + if messages.count <= block { + return [messages] + } else { + var result: [[MessageId]] = [] + var offset = 0 + while offset < messages.count { + result.append(Array(messages[offset ..< min(offset + block, messages.count)])) + offset += block + } + return result + } +} + +final class HistoryViewStateValidationContexts { + private let queue: Queue + private let postbox: Postbox + private let network: Network + private let accountPeerId: PeerId + + private var contexts: [Int32: HistoryStateValidationContext] = [:] + + init(queue: Queue, postbox: Postbox, network: Network, accountPeerId: PeerId) { + self.queue = queue + self.postbox = postbox + self.network = network + self.accountPeerId = accountPeerId + } + + func updateView(id: Int32, view: MessageHistoryView?) { + assert(self.queue.isCurrent()) + guard let view = view, view.tagMask == nil || view.tagMask == MessageTags.unseenPersonalMessage else { + if self.contexts[id] != nil { + self.contexts.removeValue(forKey: id) + } + return + } + var historyState: HistoryState? + for entry in view.additionalData { + if case let .peerChatState(peerId, chatState) = entry { + if let chatState = chatState as? ChannelState { + historyState = .channel(peerId, chatState) + } + break + } + } + + if let historyState = historyState, historyState.hasInvalidationIndex { + var rangesToInvalidate: [[MessageId]] = [] + let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in + if ranges.isEmpty { + ranges = [[id]] + } else { + ranges[ranges.count - 1].append(id) + } + } + + let addRangeBreak: (inout [[MessageId]]) -> Void = { ranges in + if ranges.last?.count != 0 { + ranges.append([]) + } + } + + for entry in view.entries { + if historyState.matchesPeerId(entry.message.id.peerId) && entry.message.id.namespace == Namespaces.Message.Cloud { + if !historyState.isMessageValid(entry.message) { + addToRange(entry.message.id, &rangesToInvalidate) + } else { + addRangeBreak(&rangesToInvalidate) + } + } + } + + if !rangesToInvalidate.isEmpty && rangesToInvalidate[rangesToInvalidate.count - 1].isEmpty { + rangesToInvalidate.removeLast() + } + + var invalidatedMessageIds = Set() + + if !rangesToInvalidate.isEmpty { + let context: HistoryStateValidationContext + if let current = self.contexts[id] { + context = current + } else { + context = HistoryStateValidationContext() + self.contexts[id] = context + } + + var addedRanges: [[MessageId]] = [] + for messages in rangesToInvalidate { + for id in messages { + invalidatedMessageIds.insert(id) + + if context.batchReferences[id] != nil { + addRangeBreak(&addedRanges) + } else { + addToRange(id, &addedRanges) + } + } + addRangeBreak(&addedRanges) + } + + if !addedRanges.isEmpty && addedRanges[addedRanges.count - 1].isEmpty { + addedRanges.removeLast() + } + + for rangeMessages in addedRanges { + for messages in slicedForValidationMessages(rangeMessages) { + let disposable = MetaDisposable() + let batch = HistoryStateValidationBatch(disposable: disposable, invalidatedState: historyState) + for messageId in messages { + context.batchReferences[messageId] = batch + } + + disposable.set((validateBatch(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, tag: view.tagMask, messageIds: messages, historyState: historyState) + |> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in + if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch { + var completedMessageIds: [MessageId] = [] + for (messageId, messageBatch) in context.batchReferences { + if messageBatch === batch { + completedMessageIds.append(messageId) + } + } + for messageId in completedMessageIds { + context.batchReferences.removeValue(forKey: messageId) + } + } + })) + } + } + } + + if let context = self.contexts[id] { + var removeIds: [MessageId] = [] + + for batchMessageId in context.batchReferences.keys { + if !invalidatedMessageIds.contains(batchMessageId) { + removeIds.append(batchMessageId) + } + } + + for messageId in removeIds { + context.batchReferences.removeValue(forKey: messageId) + } + } + } + } +} + +private func hashForMessages(_ messages: [Message], withChannelIds: Bool) -> Int32 { + var acc: UInt32 = 0 + + let sorted = messages.sorted(by: { $0.index > $1.index }) + + for message in sorted { + if withChannelIds { + acc = (acc &* 20261) &+ UInt32(message.id.peerId.id) + } + + acc = (acc &* 20261) &+ UInt32(message.id.id) + var timestamp = message.timestamp + inner: for attribute in message.attributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = attribute.date + break inner + } + } + acc = (acc &* 20261) &+ UInt32(timestamp) + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +private func hashForMessages(_ messages: [StoreMessage], withChannelIds: Bool) -> Int32 { + var acc: UInt32 = 0 + + for message in messages { + if case let .Id(id) = message.id { + if withChannelIds { + acc = (acc &* 20261) &+ UInt32(id.peerId.id) + } + acc = (acc &* 20261) &+ UInt32(id.id) + var timestamp = message.timestamp + inner: for attribute in message.attributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = attribute.date + break inner + } + } + acc = (acc &* 20261) &+ UInt32(timestamp) + } + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +private enum ValidatedMessages { + case notModified + case messages([Api.Message], [Api.Chat], [Api.User], Int32?) +} + +private func validateBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, tag: MessageTags?, messageIds: [MessageId], historyState: HistoryState) -> Signal { + return postbox.transaction { transaction -> Signal in + var previousMessages: [Message] = [] + var previous: [MessageId: Message] = [:] + for messageId in messageIds { + if let message = transaction.getMessage(messageId) { + previousMessages.append(message) + previous[message.id] = message + } + } + + var signal: Signal + switch historyState { + case let .channel(peerId, _): + let hash = hashForMessages(previousMessages, withChannelIds: false) + Logger.shared.log("HistoryValidation", "validate batch for \(peerId): \(previousMessages.map({ $0.id }))") + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + let requestSignal: Signal + if let tag = tag { + if tag == MessageTags.unseenPersonalMessage { + requestSignal = network.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id + 1, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1)) + } else { + assertionFailure() + requestSignal = .complete() + } + } else { + requestSignal = network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id + 1, offsetDate: 0, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash)) + } + + signal = requestSignal + |> map { result -> ValidatedMessages in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + var channelPts: Int32? + + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + channelPts = pts + case .messagesNotModified: + return .notModified + } + return .messages(messages, chats, users, channelPts) + } + } else { + return .complete() + } + } + + return signal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .complete() + } + switch result { + case let .messages(messages, chats, users, channelPts): + var storeMessages: [StoreMessage] = [] + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + var attributes = storeMessage.attributes + + if let channelPts = channelPts { + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + } + + storeMessages.append(storeMessage.withUpdatedAttributes(attributes)) + } + } + + var validMessageIds = Set() + for message in storeMessages { + if case let .Id(id) = message.id { + validMessageIds.insert(id) + } + } + + var maybeRemovedMessageIds: [MessageId] = [] + for id in previous.keys { + if !validMessageIds.contains(id) { + maybeRemovedMessageIds.append(id) + } + } + + let actuallyRemovedMessagesSignal: Signal, NoError> + if maybeRemovedMessageIds.isEmpty { + actuallyRemovedMessagesSignal = .single(Set()) + } else { + actuallyRemovedMessagesSignal = postbox.transaction { transaction -> Signal, NoError> in + switch historyState { + case let .channel(peerId, _): + if let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) { + return network.request(Api.functions.channels.getMessages(channel: inputChannel, id: maybeRemovedMessageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + |> map { result -> Set in + let apiMessages: [Api.Message] + switch result { + case let .channelMessages(_, _, _, messages, _, _): + apiMessages = messages + case let .messages(messages, _, _): + apiMessages = messages + case let .messagesSlice(_, _, _, messages, _, _): + apiMessages = messages + case .messagesNotModified: + return Set() + } + var ids = Set() + for message in apiMessages { + if let parsedMessage = StoreMessage(apiMessage: message), case let .Id(id) = parsedMessage.id { + if let tag = tag { + if parsedMessage.tags.contains(tag) { + ids.insert(id) + } + } else { + ids.insert(id) + } + } + } + return Set(maybeRemovedMessageIds).subtracting(ids) + } + |> `catch` { _ -> Signal, NoError> in + return .single(Set(maybeRemovedMessageIds)) + } + } + } + return .single(Set(maybeRemovedMessageIds)) + } + |> switchToLatest + } + + return actuallyRemovedMessagesSignal + |> mapToSignal { removedMessageIds -> Signal in + return postbox.transaction { transaction -> Void in + var validMessageIds = Set() + for message in storeMessages { + if case let .Id(id) = message.id { + validMessageIds.insert(id) + let previousMessage = previous[id] ?? transaction.getMessage(id) + + if let previousMessage = previousMessage { + var updatedTimestamp = message.timestamp + inner: for attribute in message.attributes { + if let attribute = attribute as? EditedMessageAttribute { + updatedTimestamp = attribute.date + break inner + } + } + + var timestamp = previousMessage.timestamp + inner: for attribute in previousMessage.attributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = attribute.date + break inner + } + } + + transaction.updateMessage(id, update: { currentMessage in + if updatedTimestamp != timestamp { + var updatedLocalTags = message.localTags + if currentMessage.localTags.contains(.OutgoingLiveLocation) { + updatedLocalTags.insert(.OutgoingLiveLocation) + } + return .update(message.withUpdatedLocalTags(updatedLocalTags)) + } else { + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + if let channelPts = channelPts { + for i in (0 ..< attributes.count).reversed() { + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + } + } + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + } + + let updatedFlags = StoreMessageFlags(currentMessage.flags) + + return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + } + }) + + if previous[id] == nil { + print("\(id) missing") + } + } else { + let _ = transaction.addMessages([message], location: .Random) + } + } + } + + if let tag = tag { + for (_, previousMessage) in previous { + if !validMessageIds.contains(previousMessage.id) { + transaction.updateMessage(previousMessage.id, update: { currentMessage in + var updatedTags = currentMessage.tags + updatedTags.remove(tag) + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + for i in (0 ..< attributes.count).reversed() { + switch historyState { + case .channel: + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + } + } + } + switch historyState { + case let .channel(_, channelState): + attributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + } + + for id in removedMessageIds { + if !validMessageIds.contains(id) { + if let tag = tag { + transaction.updateMessage(id, update: { currentMessage in + var updatedTags = currentMessage.tags + updatedTags.remove(tag) + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + for i in (0 ..< attributes.count).reversed() { + switch historyState { + case .channel: + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + } + } + } + switch historyState { + case let .channel(_, channelState): + attributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } else { + switch historyState { + case .channel: + deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [id]) + Logger.shared.log("HistoryValidation", "deleting message \(id) in \(id.peerId)") + } + } + } + } + } + } + case .notModified: + return postbox.transaction { transaction -> Void in + for id in previous.keys { + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + for i in (0 ..< attributes.count).reversed() { + switch historyState { + case .channel: + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + } + } + } + switch historyState { + case let .channel(_, channelState): + attributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + } + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/Holes.swift b/submodules/TelegramCore/TelegramCore/Holes.swift new file mode 100644 index 0000000000..5ffc3d3f3e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Holes.swift @@ -0,0 +1,569 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private func messageFilterForTagMask(_ tagMask: MessageTags) -> Api.MessagesFilter? { + if tagMask == .photoOrVideo { + return Api.MessagesFilter.inputMessagesFilterPhotoVideo + } else if tagMask == .file { + return Api.MessagesFilter.inputMessagesFilterDocument + } else if tagMask == .music { + return Api.MessagesFilter.inputMessagesFilterMusic + } else if tagMask == .webPage { + return Api.MessagesFilter.inputMessagesFilterUrl + } else if tagMask == .voiceOrInstantVideo { + return Api.MessagesFilter.inputMessagesFilterRoundVoice + } else { + return nil + } +} + +enum FetchMessageHistoryHoleSource { + case network(Network) + case download(Download) + + func request(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse)) -> Signal { + switch self { + case let .network(network): + return network.request(data) + case let .download(download): + return download.request(data) + } + } +} + +func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMessageHistoryHoleSource, peers: [PeerId: Peer], storeMessages: [StoreMessage], _ f: @escaping (Transaction, [Peer], [StoreMessage]) -> Void) -> Signal { + return postbox.transaction { transaction -> Signal in + var storedIds = Set() + var referencedIds = Set() + for message in storeMessages { + guard case let .Id(id) = message.id else { + continue + } + storedIds.insert(id) + for attribute in message.attributes { + referencedIds.formUnion(attribute.associatedMessageIds) + } + } + referencedIds.subtract(storedIds) + referencedIds.subtract(transaction.filterStoredMessageIds(referencedIds)) + + if referencedIds.isEmpty { + f(transaction, [], []) + return .complete() + } else { + var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] + for (peerId, messageIds) in messagesIdsGroupedByPeerId(referencedIds) { + if let peer = transaction.getPeer(peerId) ?? peers[peerId] { + var signal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + signal = source.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = source.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } + } + if let signal = signal { + signals.append(signal + |> map { result in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, messages, chats, users): + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } + |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + }) + } + } + } + + let fetchMessages = combineLatest(signals) + + return fetchMessages + |> mapToSignal { results -> Signal in + var additionalPeers: [Peer] = [] + var additionalMessages: [StoreMessage] = [] + for (messages, chats, users) in results { + if !messages.isEmpty { + for message in messages { + if let message = StoreMessage(apiMessage: message) { + additionalMessages.append(message) + } + } + } + for chat in chats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + additionalPeers.append(peer) + } + } + for user in users { + additionalPeers.append(TelegramUser(user: user)) + } + } + return postbox.transaction { transaction -> Void in + f(transaction, additionalPeers, additionalMessages) + } + |> ignoreValues + } + } + } + |> switchToLatest +} + +func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryHoleSource, postbox: Postbox, peerId: PeerId, namespace: MessageId.Namespace, direction: MessageHistoryViewRelativeHoleDirection, space: MessageHistoryHoleSpace, limit: Int = 100) -> Signal { + return postbox.stateView() + |> mapToSignal { view -> Signal in + if let state = view.state as? AuthorizedAccountState { + return .single(state) + } else { + return .complete() + } + } + |> take(1) + |> mapToSignal { _ -> Signal in + return postbox.loadedPeerWithId(peerId) + |> take(1) + |> mapToSignal { peer in + if let inputPeer = forceApiInputPeer(peer) { + print("fetchMessageHistoryHole for \(peer.debugDisplayTitle) \(direction) space \(space)") + Logger.shared.log("fetchMessageHistoryHole", "fetch for \(peer.debugDisplayTitle) \(direction) space \(space)") + let request: Signal + var implicitelyFillHole = false + let minMaxRange: ClosedRange + switch space { + case .everywhere: + let offsetId: Int32 + let addOffset: Int32 + let selectedLimit = limit + let maxId: Int32 + let minId: Int32 + + switch direction { + case let .range(start, end): + if start.id <= end.id { + offsetId = start.id <= 1 ? 1 : (start.id - 1) + addOffset = Int32(-selectedLimit) + maxId = end.id + minId = start.id - 1 + + let rangeStartId = start.id + let rangeEndId = min(end.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } else { + offsetId = start.id == Int32.max ? start.id : (start.id + 1) + addOffset = 0 + maxId = start.id == Int32.max ? start.id : (start.id + 1) + minId = end.id + + let rangeStartId = end.id + let rangeEndId = min(start.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } + case let .aroundId(id): + offsetId = id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + minMaxRange = 1 ... Int32.max - 1 + } + + request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: 0, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) + case let .tag(tag): + assert(tag.containsSingleElement) + if tag == .unseenPersonalMessage { + let offsetId: Int32 + let addOffset: Int32 + let selectedLimit = limit + let maxId: Int32 + let minId: Int32 + + switch direction { + case let .range(start, end): + if start.id <= end.id { + offsetId = start.id <= 1 ? 1 : (start.id - 1) + addOffset = Int32(-selectedLimit) + maxId = end.id + minId = start.id - 1 + + let rangeStartId = start.id + let rangeEndId = min(end.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } else { + offsetId = start.id == Int32.max ? start.id : (start.id + 1) + addOffset = 0 + maxId = start.id == Int32.max ? start.id : (start.id + 1) + minId = end.id + + let rangeStartId = end.id + let rangeEndId = min(start.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } + case let .aroundId(id): + offsetId = id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + + minMaxRange = 1 ... Int32.max - 1 + } + + request = source.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId)) + } else if tag == .liveLocation { + let selectedLimit = limit + + switch direction { + case .aroundId, .range: + implicitelyFillHole = true + } + minMaxRange = 1 ... (Int32.max - 1) + request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0)) + } else if let filter = messageFilterForTagMask(tag) { + let offsetId: Int32 + let addOffset: Int32 + let selectedLimit = limit + let maxId: Int32 + let minId: Int32 + + switch direction { + case let .range(start, end): + if start.id <= end.id { + offsetId = start.id <= 1 ? 1 : (start.id - 1) + addOffset = Int32(-selectedLimit) + maxId = end.id + minId = start.id - 1 + + let rangeStartId = start.id + let rangeEndId = min(end.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } else { + offsetId = start.id == Int32.max ? start.id : (start.id + 1) + addOffset = 0 + maxId = start.id == Int32.max ? start.id : (start.id + 1) + minId = end.id + + let rangeStartId = end.id + let rangeEndId = min(start.id, Int32.max - 1) + if rangeStartId <= rangeEndId { + minMaxRange = rangeStartId ... rangeEndId + } else { + minMaxRange = rangeStartId ... rangeStartId + assertionFailure() + } + } + case let .aroundId(id): + offsetId = id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + + minMaxRange = 1 ... (Int32.max - 1) + } + + request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: 0, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) + } else { + assertionFailure() + minMaxRange = 1 ... 1 + request = .never() + } + } + + return request + |> retryRequest + |> mapToSignal { result -> Signal in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + var channelPts: Int32? + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + channelPts = pts + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + var storeMessages: [StoreMessage] = [] + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + if let channelPts = channelPts { + var attributes = storeMessage.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + storeMessages.append(storeMessage.withUpdatedAttributes(attributes)) + } else { + storeMessages.append(storeMessage) + } + } + } + + return withResolvedAssociatedMessages(postbox: postbox, source: source, peers: Dictionary(peers.map({ ($0.id, $0) }), uniquingKeysWith: { lhs, _ in lhs }), storeMessages: storeMessages, { transaction, additionalPeers, additionalMessages in + let _ = transaction.addMessages(storeMessages, location: .Random) + let _ = transaction.addMessages(additionalMessages, location: .Random) + let filledRange: ClosedRange + let ids = messages.compactMap({ $0.id?.id }) + if ids.count == 0 || implicitelyFillHole { + filledRange = minMaxRange + } else { + let messageRange = ids.min()! ... ids.max()! + switch direction { + case let .aroundId(aroundId): + filledRange = min(aroundId.id, messageRange.lowerBound) ... max(aroundId.id, messageRange.lowerBound) + case let .range(start, end): + if start.id <= end.id { + let minBound = start.id + let maxBound = messageRange.upperBound + filledRange = min(minBound, maxBound) ... max(minBound, maxBound) + } else { + let minBound = messageRange.lowerBound + let maxBound = start.id + filledRange = min(minBound, maxBound) ... max(minBound, maxBound) + } + } + } + transaction.removeHole(peerId: peerId, namespace: namespace, space: space, range: filledRange) + + updatePeers(transaction: transaction, peers: peers + additionalPeers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + print("fetchMessageHistoryHole for \(peer.debugDisplayTitle) space \(space) done") + + return + }) + } + } else { + return .complete() + } + } + } +} + +func groupBoundaryPeer(_ peerId: PeerId, accountPeerId: PeerId) -> Api.Peer { + switch peerId.namespace { + case Namespaces.Peer.CloudUser: + return Api.Peer.peerUser(userId: peerId.id) + case Namespaces.Peer.CloudGroup: + return Api.Peer.peerChat(chatId: peerId.id) + case Namespaces.Peer.CloudChannel: + return Api.Peer.peerChannel(channelId: peerId.id) + default: + return Api.Peer.peerUser(userId: accountPeerId.id) + } +} + +func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId, groupId: PeerGroupId, hole: ChatListHole) -> Signal { + let location: FetchChatListLocation + switch groupId { + case .root: + location = .general + case .group: + location = .group(groupId) + } + return fetchChatList(postbox: postbox, network: network, location: location, upperBound: hole.index, hash: 0, limit: 100) + |> mapToSignal { fetchedChats -> Signal in + guard let fetchedChats = fetchedChats else { + return postbox.transaction { transaction -> Void in + transaction.replaceChatListHole(groupId: groupId, index: hole.index, hole: nil) + } + |> ignoreValues + } + return withResolvedAssociatedMessages(postbox: postbox, source: .network(network), peers: Dictionary(fetchedChats.peers.map({ ($0.id, $0) }), uniquingKeysWith: { lhs, _ in lhs }), storeMessages: fetchedChats.storeMessages, { transaction, additionalPeers, additionalMessages in + updatePeers(transaction: transaction, peers: fetchedChats.peers + additionalPeers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: fetchedChats.peerPresences) + transaction.updateCurrentPeerNotificationSettings(fetchedChats.notificationSettings) + let _ = transaction.addMessages(fetchedChats.storeMessages, location: .UpperHistoryBlock) + let _ = transaction.addMessages(additionalMessages, location: .Random) + transaction.resetIncomingReadStates(fetchedChats.readStates) + + transaction.replaceChatListHole(groupId: groupId, index: hole.index, hole: fetchedChats.lowerNonPinnedIndex.flatMap(ChatListHole.init)) + + for peerId in fetchedChats.chatPeerIds { + if let peer = transaction.getPeer(peerId) { + transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: nil, minTimestamp: minTimestampForPeerInclusion(peer))) + } else { + assertionFailure() + } + } + + for (peerId, peerGroupId) in fetchedChats.peerGroupIds { + if let peer = transaction.getPeer(peerId) { + transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: peerGroupId, pinningIndex: nil, minTimestamp: minTimestampForPeerInclusion(peer))) + } else { + assertionFailure() + } + } + + for (peerId, chatState) in fetchedChats.chatStates { + if let chatState = chatState as? ChannelState { + if let current = transaction.getPeerChatState(peerId) as? ChannelState { + transaction.setPeerChatState(peerId, state: current.withUpdatedPts(chatState.pts)) + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } + + if let replacePinnedItemIds = fetchedChats.pinnedItemIds { + transaction.setPinnedItemIds(groupId: groupId, itemIds: replacePinnedItemIds.map(PinnedItemId.peer)) + } + + for (peerId, summary) in fetchedChats.mentionTagSummaries { + transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId) + } + + for (groupId, summary) in fetchedChats.folderSummaries { + transaction.resetPeerGroupSummary(groupId: groupId, namespace: Namespaces.Message.Cloud, summary: summary) + } + }) + } +} + +func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId, holeIndex: MessageIndex, limit: Int32 = 100) -> Signal { + let offset: Signal<(Int32, Int32, Api.InputPeer), NoError> + offset = single((holeIndex.timestamp, min(holeIndex.id.id, Int32.max - 1) + 1, Api.InputPeer.inputPeerEmpty), NoError.self) + return offset + |> mapToSignal { (timestamp, id, peer) -> Signal in + let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + return postbox.transaction { transaction -> Void in + var storeMessages: [StoreMessage] = [] + var topIndex: MessageIndex? + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + storeMessages.append(storeMessage) + if let index = storeMessage.index, topIndex == nil || index < topIndex! { + topIndex = index + } + } + } + + var updatedIndex: MessageIndex? + if let topIndex = topIndex { + updatedIndex = topIndex.predecessor() + } + + transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + } + } + return searchResult + } +} diff --git a/submodules/TelegramCore/TelegramCore/ImageRepresentationsUtils.swift b/submodules/TelegramCore/TelegramCore/ImageRepresentationsUtils.swift new file mode 100644 index 0000000000..a649f38d95 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ImageRepresentationsUtils.swift @@ -0,0 +1,83 @@ +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public func smallestImageRepresentation(_ representations: [TelegramMediaImageRepresentation]) -> TelegramMediaImageRepresentation? { + if representations.count == 0 { + return nil + } else { + var dimensions = representations[0].dimensions + var index = 0 + + for i in 1 ..< representations.count { + let representationDimensions = representations[i].dimensions + if representationDimensions.width < dimensions.width && representationDimensions.height < dimensions.height { + dimensions = representationDimensions + index = i + } + } + + return representations[index] + } +} + +public func largestImageRepresentation(_ representations: [TelegramMediaImageRepresentation]) -> TelegramMediaImageRepresentation? { + if representations.count == 0 { + return nil + } else { + var dimensions = representations[0].dimensions + var index = 0 + + for i in 1 ..< representations.count { + let representationDimensions = representations[i].dimensions + if representationDimensions.width > dimensions.width && representationDimensions.height > dimensions.height { + dimensions = representationDimensions + index = i + } + } + + return representations[index] + } +} + +public func imageRepresentationLargerThan(_ representations: [TelegramMediaImageRepresentation], size: CGSize) -> TelegramMediaImageRepresentation? { + if representations.count == 0 { + return nil + } else { + var index: Int? + + for i in 0 ..< representations.count { + let representationDimensions = representations[i].dimensions + if let rindex = index { + let dimensions = representations[rindex].dimensions + if representationDimensions.width > size.width && representationDimensions.height > size.height && representationDimensions.width < dimensions.width && representationDimensions.height < dimensions.height { + index = i + } + } else { + if representationDimensions.width > size.width && representationDimensions.height > size.height { + index = i + } + } + } + + if let index = index { + return representations[index] + } else { + return largestImageRepresentation(representations) + } + } +} + +public func parseMediaData(data: Data) -> Media? { + if let object = Api.parse(Buffer(data: data)) { + if let photo = object as? Api.Photo { + return telegramMediaImageFromApiPhoto(photo) + } else if let document = object as? Api.Document { + return telegramMediaFileFromApiDocument(document) + } + } + return nil +} diff --git a/submodules/TelegramCore/TelegramCore/ImportContact.swift b/submodules/TelegramCore/TelegramCore/ImportContact.swift new file mode 100644 index 0000000000..37e0f5eb40 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ImportContact.swift @@ -0,0 +1,118 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func importContact(account: Account, firstName: String, lastName: String, phoneNumber: String) -> Signal { + + let input = Api.InputContact.inputPhoneContact(clientId: 1, phone: phoneNumber, firstName: firstName, lastName: lastName) + + return account.network.request(Api.functions.contacts.importContacts(contacts: [input])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> PeerId? in + if let result = result { + switch result { + case let .importedContacts(_, _, _, users): + if let first = users.first { + let user = TelegramUser(user: first) + let peerId = user.id + updatePeers(transaction: transaction, peers: [user], update: { _, updated in + return updated + }) + var peerIds = transaction.getContactPeerIds() + if !peerIds.contains(peerId) { + peerIds.insert(peerId) + transaction.replaceContactPeerIds(peerIds) + } + return peerId + } + } + } + return nil + } + } +} + +public enum AddContactError { + case generic +} + +public func addContactInteractively(account: Account, peerId: PeerId, firstName: String, lastName: String, phoneNumber: String) -> Signal { + return account.postbox.transaction { transaction -> (Api.InputUser, String)? in + if let user = transaction.getPeer(peerId) as? TelegramUser, let inputUser = apiInputUser(user) { + return (inputUser, user.phone == nil ? phoneNumber : "") + } else { + return nil + } + } + |> introduceError(AddContactError.self) + |> mapToSignal { inputUserAndPhone in + guard let (inputUser, phone) = inputUserAndPhone else { + return .fail(.generic) + } + return account.network.request(Api.functions.contacts.addContact(id: inputUser, firstName: firstName, lastName: lastName, phone: phone)) + |> mapError { _ -> AddContactError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + var peers: [Peer] = [] + switch result { + case let .updates(_, users, _, _, _): + for user in users { + peers.append(TelegramUser(user: user)) + } + case let .updatesCombined(_, users, _, _, _, _): + for user in users { + peers.append(TelegramUser(user: user)) + } + default: + break + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + var peerIds = transaction.getContactPeerIds() + if !peerIds.contains(peerId) { + peerIds.insert(peerId) + transaction.replaceContactPeerIds(peerIds) + } + + account.stateManager.addUpdates(result) + } + |> introduceError(AddContactError.self) + |> ignoreValues + } + } +} + +public enum AcceptAndShareContactError { + case generic +} + +public func acceptAndShareContact(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Api.InputUser? in + return transaction.getPeer(peerId).flatMap(apiInputUser) + } + |> introduceError(AcceptAndShareContactError.self) + |> mapToSignal { inputUser -> Signal in + guard let inputUser = inputUser else { + return .fail(.generic) + } + return account.network.request(Api.functions.contacts.acceptContact(id: inputUser)) + |> mapError { _ -> AcceptAndShareContactError in + return .generic + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + return .complete() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Info.plist b/submodules/TelegramCore/TelegramCore/Info.plist new file mode 100644 index 0000000000..fbe1e6b314 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/submodules/TelegramCore/TelegramCore/InitializeAccountAfterLogin.swift b/submodules/TelegramCore/TelegramCore/InitializeAccountAfterLogin.swift new file mode 100644 index 0000000000..51329eba44 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InitializeAccountAfterLogin.swift @@ -0,0 +1,21 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +func initializedAppSettingsAfterLogin(transaction: Transaction, appVersion: String, syncContacts: Bool) { + updateAppChangelogState(transaction: transaction, { state in + var state = state + state.checkedVersion = appVersion + state.previousVersion = appVersion + return state + }) + transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { _ in + return ContactsSettings(synchronizeContacts: syncContacts) + }) +} + diff --git a/submodules/TelegramCore/TelegramCore/InlineBotMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/InlineBotMessageAttribute.swift new file mode 100644 index 0000000000..c49f186678 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InlineBotMessageAttribute.swift @@ -0,0 +1,46 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class InlineBotMessageAttribute: MessageAttribute { + public let peerId: PeerId? + public let title: String? + + public var associatedPeerIds: [PeerId] { + if let peerId = self.peerId { + return [peerId] + } else { + return [] + } + } + + init(peerId: PeerId?, title: String?) { + self.peerId = peerId + self.title = title + } + + required public init(decoder: PostboxDecoder) { + if let peerId = decoder.decodeOptionalInt64ForKey("i") { + self.peerId = PeerId(peerId) + } else { + self.peerId = nil + } + self.title = decoder.decodeOptionalStringForKey("t") + } + + public func encode(_ encoder: PostboxEncoder) { + if let peerId = self.peerId { + encoder.encodeInt64(peerId.toInt64(), forKey: "i") + } else { + encoder.encodeNil(forKey: "i") + } + if let title = self.title { + encoder.encodeString(title, forKey: "t") + } else { + encoder.encodeNil(forKey: "t") + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/InstallInteractiveReadMessagesAction.swift b/submodules/TelegramCore/TelegramCore/InstallInteractiveReadMessagesAction.swift new file mode 100644 index 0000000000..5ad59d37cd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InstallInteractiveReadMessagesAction.swift @@ -0,0 +1,64 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func installInteractiveReadMessagesAction(postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Disposable { + return postbox.installStoreMessageAction(peerId: peerId, { messages, transaction in + var consumeMessageIds: [MessageId] = [] + + var readMessageIndexByNamespace: [MessageId.Namespace: MessageIndex] = [:] + + for message in messages { + if case let .Id(id) = message.id { + var hasUnconsumedMention = false + var hasUnconsumedContent = false + + if message.tags.contains(.unseenPersonalMessage) { + inner: for attribute in message.attributes { + if let attribute = attribute as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed, !attribute.pending { + hasUnconsumedMention = true + } else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed { + hasUnconsumedContent = true + } + } + } + + if hasUnconsumedMention && !hasUnconsumedContent { + consumeMessageIds.append(id) + } + + if message.flags.contains(.Incoming) { + let index = MessageIndex(id: id, timestamp: message.timestamp) + let current = readMessageIndexByNamespace[id.namespace] + if current == nil || current! < index { + readMessageIndexByNamespace[id.namespace] = index + } + } + } + } + + for id in consumeMessageIds { + transaction.updateMessage(id, update: { currentMessage in + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ConsumablePersonalMentionMessageAttribute { + attributes[j] = ConsumablePersonalMentionMessageAttribute(consumed: attribute.consumed, pending: true) + break loop + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: ConsumePersonalMessageAction()) + } + + for (_, index) in readMessageIndexByNamespace { + applyMaxReadIndexInteractively(transaction: transaction, stateManager: stateManager, index: index) + } + }) +} diff --git a/submodules/TelegramCore/TelegramCore/InstantPage.swift b/submodules/TelegramCore/TelegramCore/InstantPage.swift new file mode 100644 index 0000000000..677240c944 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InstantPage.swift @@ -0,0 +1,1101 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +private enum InstantPageBlockType: Int32 { + case unsupported = 0 + case title = 1 + case subtitle = 2 + case authorDate = 3 + case header = 4 + case subheader = 5 + case paragraph = 6 + case preformatted = 7 + case footer = 8 + case divider = 9 + case anchor = 10 + case list = 11 + case blockQuote = 12 + case pullQuote = 13 + case image = 14 + case video = 15 + case cover = 16 + case webEmbed = 17 + case postEmbed = 18 + case collage = 19 + case slideshow = 20 + case channelBanner = 21 + case audio = 22 + case kicker = 23 + case table = 24 + case details = 25 + case relatedArticles = 26 + case map = 27 +} + +private func decodeListItems(_ decoder: PostboxDecoder) -> [InstantPageListItem] { + let legacyItems: [RichText] = decoder.decodeObjectArrayWithDecoderForKey("l") + if !legacyItems.isEmpty { + var items: [InstantPageListItem] = [] + for item in legacyItems { + items.append(.text(item, nil)) + } + return items + } + return decoder.decodeObjectArrayWithDecoderForKey("ml") +} + +private func decodeCaption(_ decoder: PostboxDecoder) -> InstantPageCaption { + if let legacyCaption = decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as? RichText { + return InstantPageCaption(text: legacyCaption, credit: .empty) + } + return decoder.decodeObjectForKey("mc", decoder: { InstantPageCaption(decoder: $0) }) as! InstantPageCaption +} + +public indirect enum InstantPageBlock: PostboxCoding, Equatable { + case unsupported + case title(RichText) + case subtitle(RichText) + case authorDate(author: RichText, date: Int32) + case header(RichText) + case subheader(RichText) + case paragraph(RichText) + case preformatted(RichText) + case footer(RichText) + case divider + case anchor(String) + case list(items: [InstantPageListItem], ordered: Bool) + case blockQuote(text: RichText, caption: RichText) + case pullQuote(text: RichText, caption: RichText) + case image(id: MediaId, caption: InstantPageCaption, url: String?, webpageId: MediaId?) + case video(id: MediaId, caption: InstantPageCaption, autoplay: Bool, loop: Bool) + case audio(id: MediaId, caption: InstantPageCaption) + case cover(InstantPageBlock) + case webEmbed(url: String?, html: String?, dimensions: CGSize?, caption: InstantPageCaption, stretchToWidth: Bool, allowScrolling: Bool, coverId: MediaId?) + case postEmbed(url: String, webpageId: MediaId?, avatarId: MediaId?, author: String, date: Int32, blocks: [InstantPageBlock], caption: InstantPageCaption) + case collage(items: [InstantPageBlock], caption: InstantPageCaption) + case slideshow(items: [InstantPageBlock], caption: InstantPageCaption) + case channelBanner(TelegramChannel?) + case kicker(RichText) + case table(title: RichText, rows: [InstantPageTableRow], bordered: Bool, striped: Bool) + case details(title: RichText, blocks: [InstantPageBlock], expanded: Bool) + case relatedArticles(title: RichText, articles: [InstantPageRelatedArticle]) + case map(latitude: Double, longitude: Double, zoom: Int32, dimensions: CGSize, caption: InstantPageCaption) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case InstantPageBlockType.unsupported.rawValue: + self = .unsupported + case InstantPageBlockType.title.rawValue: + self = .title(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.subtitle.rawValue: + self = .subtitle(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.authorDate.rawValue: + self = .authorDate(author: decoder.decodeObjectForKey("a", decoder: { RichText(decoder: $0) }) as! RichText, date: decoder.decodeInt32ForKey("d", orElse: 0)) + case InstantPageBlockType.header.rawValue: + self = .header(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.subheader.rawValue: + self = .subheader(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.paragraph.rawValue: + self = .paragraph(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.preformatted.rawValue: + self = .preformatted(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.footer.rawValue: + self = .footer(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.divider.rawValue: + self = .divider + case InstantPageBlockType.anchor.rawValue: + self = .anchor(decoder.decodeStringForKey("s", orElse: "")) + case InstantPageBlockType.list.rawValue: + self = .list(items: decodeListItems(decoder), ordered: decoder.decodeOptionalInt32ForKey("o") != 0) + case InstantPageBlockType.blockQuote.rawValue: + self = .blockQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.pullQuote.rawValue: + self = .pullQuote(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, caption: decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.image.rawValue: + var webpageId: MediaId? + if let webpageIdNamespace = decoder.decodeOptionalInt32ForKey("wi.n"), let webpageIdId = decoder.decodeOptionalInt64ForKey("wi.i") { + webpageId = MediaId(namespace: webpageIdNamespace, id: webpageIdId) + } + self = .image(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), caption: decodeCaption(decoder), url: decoder.decodeOptionalStringForKey("u"), webpageId: webpageId) + case InstantPageBlockType.video.rawValue: + self = .video(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), caption: decodeCaption(decoder), autoplay: decoder.decodeInt32ForKey("ap", orElse: 0) != 0, loop: decoder.decodeInt32ForKey("lo", orElse: 0) != 0) + case InstantPageBlockType.cover.rawValue: + self = .cover(decoder.decodeObjectForKey("c", decoder: { InstantPageBlock(decoder: $0) }) as! InstantPageBlock) + case InstantPageBlockType.webEmbed.rawValue: + var coverId: MediaId? + if let coverIdNamespace = decoder.decodeOptionalInt32ForKey("ci.n"), let coverIdId = decoder.decodeOptionalInt64ForKey("ci.i") { + coverId = MediaId(namespace: coverIdNamespace, id: coverIdId) + } + var dimensions: CGSize? + if let width = decoder.decodeOptionalInt32ForKey("sw"), let height = decoder.decodeOptionalInt32ForKey("sh") { + dimensions = CGSize(width: CGFloat(width), height: CGFloat(height)) + } + self = .webEmbed(url: decoder.decodeOptionalStringForKey("u"), html: decoder.decodeOptionalStringForKey("h"), dimensions: dimensions, caption: decodeCaption(decoder), stretchToWidth: decoder.decodeInt32ForKey("st", orElse: 0) != 0, allowScrolling: decoder.decodeInt32ForKey("as", orElse: 0) != 0, coverId: coverId) + case InstantPageBlockType.postEmbed.rawValue: + var avatarId: MediaId? + let avatarIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("av.n") + let avatarIdId: Int64? = decoder.decodeOptionalInt64ForKey("av.i") + if let avatarIdNamespace = avatarIdNamespace, let avatarIdId = avatarIdId { + avatarId = MediaId(namespace: avatarIdNamespace, id: avatarIdId) + } + self = .postEmbed(url: decoder.decodeStringForKey("u", orElse: ""), webpageId: MediaId(namespace: decoder.decodeInt32ForKey("w.n", orElse: 0), id: decoder.decodeInt64ForKey("w.i", orElse: 0)), avatarId: avatarId, author: decoder.decodeStringForKey("a", orElse: ""), date: decoder.decodeInt32ForKey("d", orElse: 0), blocks: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decodeCaption(decoder)) + case InstantPageBlockType.collage.rawValue: + self = .collage(items: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decodeCaption(decoder)) + case InstantPageBlockType.slideshow.rawValue: + self = .slideshow(items: decoder.decodeObjectArrayWithDecoderForKey("b"), caption: decodeCaption(decoder)) + case InstantPageBlockType.channelBanner.rawValue: + self = .channelBanner(decoder.decodeObjectForKey("c") as? TelegramChannel) + case InstantPageBlockType.audio.rawValue: + self = .audio(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), caption: decodeCaption(decoder)) + case InstantPageBlockType.kicker.rawValue: + self = .kicker(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case InstantPageBlockType.table.rawValue: + self = .table(title: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, rows: decoder.decodeObjectArrayWithDecoderForKey("r"), bordered: decoder.decodeInt32ForKey("b", orElse: 0) != 0, striped: decoder.decodeInt32ForKey("s", orElse: 0) != 0) + case InstantPageBlockType.details.rawValue: + self = .details(title: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, blocks: decoder.decodeObjectArrayWithDecoderForKey("b"), expanded: decoder.decodeInt32ForKey("o", orElse: 0) != 0) + case InstantPageBlockType.relatedArticles.rawValue: + self = .relatedArticles(title: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, articles: decoder.decodeObjectArrayWithDecoderForKey("a")) + case InstantPageBlockType.map.rawValue: + self = .map(latitude: decoder.decodeDoubleForKey("lat", orElse: 0.0), longitude: decoder.decodeDoubleForKey("lon", orElse: 0.0), zoom: decoder.decodeInt32ForKey("z", orElse: 0), dimensions: CGSize(width: CGFloat(decoder.decodeInt32ForKey("sw", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("sh", orElse: 0))), caption: decodeCaption(decoder)) + default: + self = .unsupported + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .unsupported: + encoder.encodeInt32(InstantPageBlockType.unsupported.rawValue, forKey: "r") + case let .title(text): + encoder.encodeInt32(InstantPageBlockType.title.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .subtitle(text): + encoder.encodeInt32(InstantPageBlockType.subtitle.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .authorDate(author, date): + encoder.encodeInt32(InstantPageBlockType.authorDate.rawValue, forKey: "r") + encoder.encodeObject(author, forKey: "a") + encoder.encodeInt32(date, forKey: "d") + case let .header(text): + encoder.encodeInt32(InstantPageBlockType.header.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .subheader(text): + encoder.encodeInt32(InstantPageBlockType.subheader.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .paragraph(text): + encoder.encodeInt32(InstantPageBlockType.paragraph.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .preformatted(text): + encoder.encodeInt32(InstantPageBlockType.preformatted.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .footer(text): + encoder.encodeInt32(InstantPageBlockType.footer.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case .divider: + encoder.encodeInt32(InstantPageBlockType.divider.rawValue, forKey: "r") + case let .anchor(anchor): + encoder.encodeInt32(InstantPageBlockType.anchor.rawValue, forKey: "r") + encoder.encodeString(anchor, forKey: "s") + case let .list(items, ordered): + encoder.encodeInt32(InstantPageBlockType.list.rawValue, forKey: "r") + encoder.encodeObjectArray(items, forKey: "ml") + encoder.encodeInt32(ordered ? 1 : 0, forKey: "o") + case let .blockQuote(text, caption): + encoder.encodeInt32(InstantPageBlockType.blockQuote.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeObject(caption, forKey: "c") + case let .pullQuote(text, caption): + encoder.encodeInt32(InstantPageBlockType.pullQuote.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeObject(caption, forKey: "c") + case let .image(id, caption, url, webpageId): + encoder.encodeInt32(InstantPageBlockType.image.rawValue, forKey: "r") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt64(id.id, forKey: "i.i") + encoder.encodeObject(caption, forKey: "mc") + if let url = url { + encoder.encodeString(url, forKey: "u") + } else { + encoder.encodeNil(forKey: "u") + } + if let webpageId = webpageId { + encoder.encodeInt32(webpageId.namespace, forKey: "wi.n") + encoder.encodeInt64(webpageId.id, forKey: "wi.i") + } else { + encoder.encodeNil(forKey: "wi.n") + encoder.encodeNil(forKey: "wi.i") + } + case let .video(id, caption, autoplay, loop): + encoder.encodeInt32(InstantPageBlockType.video.rawValue, forKey: "r") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt64(id.id, forKey: "i.i") + encoder.encodeObject(caption, forKey: "mc") + encoder.encodeInt32(autoplay ? 1 : 0, forKey: "ap") + encoder.encodeInt32(loop ? 1 : 0, forKey: "lo") + case let .cover(block): + encoder.encodeInt32(InstantPageBlockType.cover.rawValue, forKey: "r") + encoder.encodeObject(block, forKey: "c") + case let .webEmbed(url, html, dimensions, caption, stretchToWidth, allowScrolling, coverId): + encoder.encodeInt32(InstantPageBlockType.webEmbed.rawValue, forKey: "r") + if let coverId = coverId { + encoder.encodeInt32(coverId.namespace, forKey: "ci.n") + encoder.encodeInt64(coverId.id, forKey: "ci.i") + } else { + encoder.encodeNil(forKey: "ci.n") + encoder.encodeNil(forKey: "ci.i") + } + if let url = url { + encoder.encodeString(url, forKey: "u") + } else { + encoder.encodeNil(forKey: "u") + } + if let html = html { + encoder.encodeString(html, forKey: "h") + } else { + encoder.encodeNil(forKey: "h") + } + if let dimensions = dimensions { + encoder.encodeInt32(Int32(dimensions.width), forKey: "sw") + encoder.encodeInt32(Int32(dimensions.height), forKey: "sh") + } else { + encoder.encodeNil(forKey: "sw") + encoder.encodeNil(forKey: "sh") + } + encoder.encodeObject(caption, forKey: "mc") + encoder.encodeInt32(stretchToWidth ? 1 : 0, forKey: "st") + encoder.encodeInt32(allowScrolling ? 1 : 0, forKey: "as") + case let .postEmbed(url, webpageId, avatarId, author, date, blocks, caption): + encoder.encodeInt32(InstantPageBlockType.postEmbed.rawValue, forKey: "r") + if let avatarId = avatarId { + encoder.encodeInt32(avatarId.namespace, forKey: "av.n") + encoder.encodeInt64(avatarId.id, forKey: "av.i") + } else { + encoder.encodeNil(forKey: "av.n") + encoder.encodeNil(forKey: "av.i") + } + encoder.encodeString(url, forKey: "u") + if let webpageId = webpageId { + encoder.encodeInt32(webpageId.namespace, forKey: "w.n") + encoder.encodeInt64(webpageId.id, forKey: "w.i") + } else { + encoder.encodeNil(forKey: "w.n") + encoder.encodeNil(forKey: "w.i") + } + encoder.encodeString(author, forKey: "a") + encoder.encodeInt32(date, forKey: "d") + encoder.encodeObjectArray(blocks, forKey: "b") + encoder.encodeObject(caption, forKey: "mc") + case let .collage(items, caption): + encoder.encodeInt32(InstantPageBlockType.collage.rawValue, forKey: "r") + encoder.encodeObjectArray(items, forKey: "b") + encoder.encodeObject(caption, forKey: "mc") + case let .slideshow(items, caption): + encoder.encodeInt32(InstantPageBlockType.slideshow.rawValue, forKey: "r") + encoder.encodeObjectArray(items, forKey: "b") + encoder.encodeObject(caption, forKey: "mc") + case let .channelBanner(channel): + encoder.encodeInt32(InstantPageBlockType.channelBanner.rawValue, forKey: "r") + if let channel = channel { + encoder.encodeObject(channel, forKey: "c") + } else { + encoder.encodeNil(forKey: "c") + } + case let .audio(id, caption): + encoder.encodeInt32(InstantPageBlockType.audio.rawValue, forKey: "r") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt64(id.id, forKey: "i.i") + encoder.encodeObject(caption, forKey: "mc") + case let .kicker(text): + encoder.encodeInt32(InstantPageBlockType.kicker.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .table(title, rows, bordered, striped): + encoder.encodeInt32(InstantPageBlockType.table.rawValue, forKey: "r") + encoder.encodeObject(title, forKey: "t") + encoder.encodeObjectArray(rows, forKey: "r") + encoder.encodeInt32(bordered ? 1 : 0, forKey: "b") + encoder.encodeInt32(striped ? 1 : 0, forKey: "s") + case let .details(title, blocks, expanded): + encoder.encodeInt32(InstantPageBlockType.details.rawValue, forKey: "r") + encoder.encodeObject(title, forKey: "t") + encoder.encodeObjectArray(blocks, forKey: "b") + encoder.encodeInt32(expanded ? 1 : 0, forKey: "o") + case let .relatedArticles(title, articles): + encoder.encodeInt32(InstantPageBlockType.relatedArticles.rawValue, forKey: "r") + encoder.encodeObject(title, forKey: "t") + encoder.encodeObjectArray(articles, forKey: "a") + case let .map(latitude, longitude, zoom, dimensions, caption): + encoder.encodeInt32(InstantPageBlockType.map.rawValue, forKey: "r") + encoder.encodeDouble(latitude, forKey: "lat") + encoder.encodeDouble(longitude, forKey: "lon") + encoder.encodeInt32(zoom, forKey: "z") + encoder.encodeInt32(Int32(dimensions.width), forKey: "sw") + encoder.encodeInt32(Int32(dimensions.height), forKey: "sh") + encoder.encodeObject(caption, forKey: "mc") + } + } + + public static func ==(lhs: InstantPageBlock, rhs: InstantPageBlock) -> Bool { + switch lhs { + case .unsupported: + if case .unsupported = rhs { + return true + } else { + return false + } + case let .title(text): + if case .title(text) = rhs { + return true + } else { + return false + } + case let .subtitle(text): + if case .subtitle(text) = rhs { + return true + } else { + return false + } + case let .authorDate(author, date): + if case .authorDate(author, date) = rhs { + return true + } else { + return false + } + case let .header(text): + if case .header(text) = rhs { + return true + } else { + return false + } + case let .subheader(text): + if case .subheader(text) = rhs { + return true + } else { + return false + } + case let .paragraph(text): + if case .paragraph(text) = rhs { + return true + } else { + return false + } + case let .preformatted(text): + if case .preformatted(text) = rhs { + return true + } else { + return false + } + case let .footer(text): + if case .footer(text) = rhs { + return true + } else { + return false + } + case .divider: + if case .divider = rhs { + return true + } else { + return false + } + case let .anchor(anchor): + if case .anchor(anchor) = rhs { + return true + } else { + return false + } + case let .list(lhsItems, lhsOrdered): + if case let .list(rhsItems, rhsOrdered) = rhs, lhsItems == rhsItems, lhsOrdered == rhsOrdered { + return true + } else { + return false + } + case let .blockQuote(text, caption): + if case .blockQuote(text, caption) = rhs { + return true + } else { + return false + } + case let .pullQuote(text, caption): + if case .pullQuote(text, caption) = rhs { + return true + } else { + return false + } + case let .image(lhsId, lhsCaption, lhsUrl, lhsWebpageId): + if case let .image(rhsId, rhsCaption, rhsUrl, rhsWebpageId) = rhs, lhsId == rhsId, lhsCaption == rhsCaption, lhsUrl == rhsUrl, lhsWebpageId == rhsWebpageId { + return true + } else { + return false + } + case let .video(id, caption, autoplay, loop): + if case .video(id, caption, autoplay, loop) = rhs { + return true + } else { + return false + } + case let .cover(block): + if case .cover(block) = rhs { + return true + } else { + return false + } + case let .webEmbed(lhsUrl, lhsHtml, lhsDimensions, lhsCaption, lhsStretchToWidth, lhsAllowScrolling, lhsCoverId): + if case let .webEmbed(rhsUrl, rhsHtml, rhsDimensions, rhsCaption, rhsStretchToWidth, rhsAllowScrolling, rhsCoverId) = rhs, lhsUrl == rhsUrl && lhsHtml == rhsHtml && lhsDimensions == rhsDimensions && lhsCaption == rhsCaption && lhsStretchToWidth == rhsStretchToWidth && lhsAllowScrolling == rhsAllowScrolling && lhsCoverId == rhsCoverId { + return true + } else { + return false + } + case let .postEmbed(lhsUrl, lhsWebpageId, lhsAvatarId, lhsAuthor, lhsDate, lhsBlocks, lhsCaption): + if case let .postEmbed(rhsUrl, rhsWebpageId, rhsAvatarId, rhsAuthor, rhsDate, rhsBlocks, rhsCaption) = rhs, lhsUrl == rhsUrl && lhsWebpageId == rhsWebpageId && lhsAvatarId == rhsAvatarId && lhsAuthor == rhsAuthor && lhsDate == rhsDate && lhsBlocks == rhsBlocks && lhsCaption == rhsCaption { + return true + } else { + return false + } + case let .collage(lhsItems, lhsCaption): + if case let .collage(rhsItems, rhsCaption) = rhs, lhsItems == rhsItems && lhsCaption == rhsCaption { + return true + } else { + return false + } + case let .slideshow(lhsItems, lhsCaption): + if case let .slideshow(rhsItems, rhsCaption) = rhs, lhsItems == rhsItems && lhsCaption == rhsCaption { + return true + } else { + return false + } + case let .channelBanner(lhsChannel): + if case let .channelBanner(rhsChannel) = rhs { + if let lhsChannel = lhsChannel, let rhsChannel = rhsChannel { + if !lhsChannel.isEqual(rhsChannel) { + return false + } + } else if (lhsChannel != nil) != (rhsChannel != nil) { + return false + } + return true + } else { + return false + } + case let .audio(id, caption): + if case .audio(id, caption) = rhs { + return true + } else { + return false + } + case let .kicker(text): + if case .kicker(text) = rhs { + return true + } else { + return false + } + case let .table(lhsTitle, lhsRows, lhsBordered, lhsStriped): + if case let .table(rhsTitle, rhsRows, rhsBordered, rhsStriped) = rhs, lhsTitle == rhsTitle, lhsRows == rhsRows, lhsBordered == rhsBordered, lhsStriped == rhsStriped { + return true + } else { + return false + } + case let .details(lhsTitle, lhsBlocks, lhsExpanded): + if case let .details(rhsTitle, rhsBlocks, rhsExpanded) = rhs, lhsTitle == rhsTitle, lhsBlocks == rhsBlocks, lhsExpanded == rhsExpanded { + return true + } else { + return false + } + case let .relatedArticles(lhsTitle, lhsArticles): + if case let .relatedArticles(rhsTitle, rhsArticles) = rhs, lhsTitle == rhsTitle, lhsArticles == rhsArticles { + return true + } else { + return false + } + case let .map(latitude, longitude, zoom, dimensions, caption): + if case .map(latitude, longitude, zoom, dimensions, caption) = rhs { + return true + } else { + return false + } + } + } +} + +public final class InstantPageCaption: PostboxCoding, Equatable { + public let text: RichText + public let credit: RichText + + init(text: RichText, credit: RichText) { + self.text = text + self.credit = credit + } + + public init(decoder: PostboxDecoder) { + self.text = decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText + self.credit = decoder.decodeObjectForKey("c", decoder: { RichText(decoder: $0) }) as! RichText + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.text, forKey: "t") + encoder.encodeObject(self.credit, forKey: "c") + } + + public static func ==(lhs: InstantPageCaption, rhs: InstantPageCaption) -> Bool { + if lhs.text != rhs.text { + return false + } + if lhs.credit != rhs.credit { + return false + } + return true + } +} + +private enum InstantPageListItemType: Int32 { + case unknown = 0 + case text = 1 + case blocks = 2 +} + +public indirect enum InstantPageListItem: PostboxCoding, Equatable { + case unknown + case text(RichText, String?) + case blocks([InstantPageBlock], String?) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case InstantPageListItemType.text.rawValue: + self = .text(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, decoder.decodeOptionalStringForKey("n")) + case InstantPageListItemType.blocks.rawValue: + self = .blocks(decoder.decodeObjectArrayWithDecoderForKey("b"), decoder.decodeOptionalStringForKey("n")) + default: + self = .unknown + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .text(text, num): + encoder.encodeInt32(InstantPageListItemType.text.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + if let num = num { + encoder.encodeString(num, forKey: "n") + } else { + encoder.encodeNil(forKey: "n") + } + case let .blocks(blocks, num): + encoder.encodeInt32(InstantPageListItemType.blocks.rawValue, forKey: "r") + encoder.encodeObjectArray(blocks, forKey: "b") + if let num = num { + encoder.encodeString(num, forKey: "n") + } else { + encoder.encodeNil(forKey: "n") + } + default: + break + } + } + + public static func ==(lhs: InstantPageListItem, rhs: InstantPageListItem) -> Bool { + switch lhs { + case .unknown: + if case .unknown = rhs { + return true + } else { + return false + } + case let .text(lhsText, lhsNum): + if case let .text(rhsText, rhsNum) = rhs, lhsText == rhsText, lhsNum == rhsNum { + return true + } else { + return false + } + case let .blocks(lhsBlocks, lhsNum): + if case let .blocks(rhsBlocks, rhsNum) = rhs, lhsBlocks == rhsBlocks, lhsNum == rhsNum { + return true + } else { + return false + } + } + } +} + +public enum TableHorizontalAlignment: Int32 { + case left = 0 + case center = 1 + case right = 2 +} + +public enum TableVerticalAlignment: Int32 { + case top = 0 + case middle = 1 + case bottom = 2 +} + +public final class InstantPageTableCell: PostboxCoding, Equatable { + public let text: RichText? + public let header: Bool + public let alignment: TableHorizontalAlignment + public let verticalAlignment: TableVerticalAlignment + public let colspan: Int32 + public let rowspan: Int32 + + public init(text: RichText?, header: Bool, alignment: TableHorizontalAlignment, verticalAlignment: TableVerticalAlignment, colspan: Int32, rowspan: Int32) { + self.text = text + self.header = header + self.alignment = alignment + self.verticalAlignment = verticalAlignment + self.colspan = colspan + self.rowspan = rowspan + } + + public init(decoder: PostboxDecoder) { + self.text = decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as? RichText + self.header = decoder.decodeInt32ForKey("h", orElse: 0) != 0 + self.alignment = TableHorizontalAlignment(rawValue: decoder.decodeInt32ForKey("ha", orElse: 0))! + self.verticalAlignment = TableVerticalAlignment(rawValue: decoder.decodeInt32ForKey("va", orElse: 0))! + self.colspan = decoder.decodeInt32ForKey("sc", orElse: 0) + self.rowspan = decoder.decodeInt32ForKey("sr", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + if let text = self.text { + encoder.encodeObject(text, forKey: "t") + } else { + encoder.encodeNil(forKey: "t") + } + encoder.encodeInt32(self.header ? 1 : 0, forKey: "h") + encoder.encodeInt32(self.alignment.rawValue, forKey: "ha") + encoder.encodeInt32(self.verticalAlignment.rawValue, forKey: "va") + encoder.encodeInt32(self.colspan, forKey: "sc") + encoder.encodeInt32(self.rowspan, forKey: "sr") + } + + public static func ==(lhs: InstantPageTableCell, rhs: InstantPageTableCell) -> Bool { + if lhs.text != rhs.text { + return false + } + if lhs.header != rhs.header { + return false + } + if lhs.alignment != rhs.alignment { + return false + } + if lhs.verticalAlignment != rhs.verticalAlignment { + return false + } + if lhs.colspan != rhs.colspan { + return false + } + if lhs.rowspan != rhs.rowspan { + return false + } + return true + } +} + +public final class InstantPageTableRow: PostboxCoding, Equatable { + public let cells: [InstantPageTableCell] + + public init(cells: [InstantPageTableCell]) { + self.cells = cells + } + + public init(decoder: PostboxDecoder) { + self.cells = decoder.decodeObjectArrayWithDecoderForKey("c") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.cells, forKey: "c") + } + + public static func ==(lhs: InstantPageTableRow, rhs: InstantPageTableRow) -> Bool { + return lhs.cells == rhs.cells + } +} + +public final class InstantPageRelatedArticle: PostboxCoding, Equatable { + public let url: String + public let webpageId: MediaId + public let title: String? + public let description: String? + public let photoId: MediaId? + public let author: String? + public let date: Int32? + + init(url: String, webpageId: MediaId, title: String?, description: String?, photoId: MediaId?, author: String?, date: Int32?) { + self.url = url + self.webpageId = webpageId + self.title = title + self.description = description + self.photoId = photoId + self.author = author + self.date = date + } + + public init(decoder: PostboxDecoder) { + self.url = decoder.decodeStringForKey("u", orElse: "") + let webpageIdNamespace = decoder.decodeInt32ForKey("w.n", orElse: 0) + let webpageIdId = decoder.decodeInt64ForKey("w.i", orElse: 0) + self.webpageId = MediaId(namespace: webpageIdNamespace, id: webpageIdId) + + self.title = decoder.decodeOptionalStringForKey("t") + self.description = decoder.decodeOptionalStringForKey("d") + + var photoId: MediaId? + if let photoIdNamespace = decoder.decodeOptionalInt32ForKey("p.n"), let photoIdId = decoder.decodeOptionalInt64ForKey("p.i") { + photoId = MediaId(namespace: photoIdNamespace, id: photoIdId) + } + self.photoId = photoId + self.author = decoder.decodeOptionalStringForKey("a") + self.date = decoder.decodeOptionalInt32ForKey("d") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.url, forKey: "u") + encoder.encodeInt32(self.webpageId.namespace, forKey: "w.n") + encoder.encodeInt64(self.webpageId.id, forKey: "w.i") + if let title = self.title { + encoder.encodeString(title, forKey: "t") + } else { + encoder.encodeNil(forKey: "t") + } + if let description = self.description { + encoder.encodeString(description, forKey: "d") + } else { + encoder.encodeNil(forKey: "d") + } + if let photoId = photoId { + encoder.encodeInt32(photoId.namespace, forKey: "p.n") + encoder.encodeInt64(photoId.id, forKey: "p.i") + } else { + encoder.encodeNil(forKey: "p.n") + encoder.encodeNil(forKey: "p.i") + } + if let author = self.author { + encoder.encodeString(author, forKey: "a") + } else { + encoder.encodeNil(forKey: "a") + } + if let date = self.date { + encoder.encodeInt32(date, forKey: "d") + } else { + encoder.encodeNil(forKey: "d") + } + } + + public static func ==(lhs: InstantPageRelatedArticle, rhs: InstantPageRelatedArticle) -> Bool { + if lhs.url != rhs.url { + return false + } + if lhs.webpageId != rhs.webpageId { + return false + } + if lhs.title != rhs.title { + return false + } + if lhs.description != rhs.description { + return false + } + if lhs.photoId != rhs.photoId { + return false + } + if lhs.author != rhs.author { + return false + } + if lhs.date != rhs.date { + return false + } + return true + } +} + +private final class MediaDictionary: PostboxCoding { + let dict: [MediaId: Media] + + init(dict: [MediaId: Media]) { + self.dict = dict + } + + init(decoder: PostboxDecoder) { + let idsBufer = decoder.decodeBytesForKey("i")! + let mediaIds = MediaId.decodeArrayFromBuffer(idsBufer) + let medias = decoder.decodeObjectArrayForKey("m") + var dict: [MediaId: Media] = [:] + assert(mediaIds.count == medias.count) + for i in 0 ..< mediaIds.count { + if let media = medias[i] as? Media { + dict[mediaIds[i]] = media + } + } + self.dict = dict + } + + func encode(_ encoder: PostboxEncoder) { + var mediaIds: [MediaId] = [] + var medias: [PostboxCoding] = [] + for mediaId in self.dict.keys { + mediaIds.append(mediaId) + medias.append(self.dict[mediaId]!) + } + let buffer = WriteBuffer() + MediaId.encodeArrayToBuffer(mediaIds, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "i") + encoder.encodeGenericObjectArray(medias, forKey: "m") + } +} + +public final class InstantPage: PostboxCoding, Equatable { + public let blocks: [InstantPageBlock] + public let media: [MediaId: Media] + public let isComplete: Bool + public let rtl: Bool + public let url: String + + init(blocks: [InstantPageBlock], media: [MediaId: Media], isComplete: Bool, rtl: Bool, url: String) { + self.blocks = blocks + self.media = media + self.isComplete = isComplete + self.rtl = rtl + self.url = url + } + + public init(decoder: PostboxDecoder) { + self.blocks = decoder.decodeObjectArrayWithDecoderForKey("b") + self.media = MediaDictionary(decoder: decoder).dict + self.isComplete = decoder.decodeInt32ForKey("c", orElse: 0) != 0 + self.rtl = decoder.decodeInt32ForKey("r", orElse: 0) != 0 + self.url = decoder.decodeStringForKey("url", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.blocks, forKey: "b") + MediaDictionary(dict: self.media).encode(encoder) + encoder.encodeInt32(self.isComplete ? 1 : 0, forKey: "c") + encoder.encodeInt32(self.rtl ? 1 : 0, forKey: "r") + encoder.encodeString(self.url, forKey: "url") + } + + public static func ==(lhs: InstantPage, rhs: InstantPage) -> Bool { + if lhs.blocks != rhs.blocks { + return false + } + if lhs.media.count != rhs.media.count { + return false + } else { + for (lhsKey, lhsValue) in lhs.media { + if let media = rhs.media[lhsKey] { + if !lhsValue.isEqual(to: media) { + return false + } + } else { + return false + } + } + } + if lhs.isComplete != rhs.isComplete { + return false + } + if lhs.rtl != rhs.rtl { + return false + } + if lhs.url != rhs.url { + return false + } + return true + } +} + +extension InstantPageCaption { + convenience init(apiCaption: Api.PageCaption) { + switch apiCaption { + case let .pageCaption(text, credit): + self.init(text: RichText(apiText: text), credit: RichText(apiText: credit)) + } + } +} + +public extension InstantPageListItem { + public var num: String? { + switch self { + case let .text(_, num): + return num + case let .blocks(_, num): + return num + default: + return nil + } + } +} + +extension InstantPageListItem { + init(apiListItem: Api.PageListItem) { + switch apiListItem { + case let .pageListItemText(text): + self = .text(RichText(apiText: text), nil) + case let .pageListItemBlocks(blocks): + self = .blocks(blocks.map({ InstantPageBlock(apiBlock: $0) }), nil) + } + } + + init(apiListOrderedItem: Api.PageListOrderedItem) { + switch apiListOrderedItem { + case let .pageListOrderedItemText(num, text): + self = .text(RichText(apiText: text), num) + case let .pageListOrderedItemBlocks(num, blocks): + self = .blocks(blocks.map({ InstantPageBlock(apiBlock: $0) }), num) + } + } +} + +extension InstantPageTableCell { + convenience init(apiTableCell: Api.PageTableCell) { + switch apiTableCell { + case let .pageTableCell(flags, text, colspan, rowspan): + var alignment = TableHorizontalAlignment.left + if (flags & (1 << 3)) != 0 { + alignment = .center + } else if (flags & (1 << 4)) != 0 { + alignment = .right + } + var verticalAlignment = TableVerticalAlignment.top + if (flags & (1 << 5)) != 0 { + verticalAlignment = .middle + } else if (flags & (1 << 6)) != 0 { + verticalAlignment = .bottom + } + self.init(text: text != nil ? RichText(apiText: text!) : nil, header: (flags & (1 << 0)) != 0, alignment: alignment, verticalAlignment: verticalAlignment, colspan: colspan ?? 0, rowspan: rowspan ?? 0) + } + } +} + +extension InstantPageTableRow { + convenience init(apiTableRow: Api.PageTableRow) { + switch apiTableRow { + case let .pageTableRow(cells): + self.init(cells: cells.map({ InstantPageTableCell(apiTableCell: $0) })) + } + } +} + +extension InstantPageRelatedArticle { + convenience init(apiRelatedArticle: Api.PageRelatedArticle) { + switch apiRelatedArticle { + case let .pageRelatedArticle(flags, url, webpageId, title, description, photoId, author, publishedDate): + var posterPhotoId: MediaId? + if let photoId = photoId { + posterPhotoId = MediaId(namespace: Namespaces.Media.CloudImage, id: photoId) + } + self.init(url: url, webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId), title: title, description: description, photoId: posterPhotoId, author: author, date: publishedDate) + } + } +} + +extension InstantPageBlock { + init(apiBlock: Api.PageBlock) { + switch apiBlock { + case .pageBlockUnsupported: + self = .unsupported + case let .pageBlockTitle(text): + self = .title(RichText(apiText: text)) + case let .pageBlockSubtitle(text): + self = .subtitle(RichText(apiText: text)) + case let .pageBlockAuthorDate(author, publishedDate): + self = .authorDate(author: RichText(apiText: author), date: publishedDate) + case let .pageBlockHeader(text): + self = .header(RichText(apiText: text)) + case let .pageBlockSubheader(text): + self = .subheader(RichText(apiText: text)) + case let .pageBlockParagraph(text): + self = .paragraph(RichText(apiText: text)) + case let .pageBlockPreformatted(text, _): + self = .preformatted(RichText(apiText: text)) + case let .pageBlockFooter(text): + self = .footer(RichText(apiText: text)) + case .pageBlockDivider: + self = .divider + case let .pageBlockAnchor(name): + self = .anchor(name) + case let .pageBlockBlockquote(text, caption): + self = .blockQuote(text: RichText(apiText: text), caption: RichText(apiText: caption)) + case let .pageBlockPullquote(text, caption): + self = .pullQuote(text: RichText(apiText: text), caption: RichText(apiText: caption)) + case let .pageBlockPhoto(flags, photoId, caption, url, webpageId): + var webpageMediaId: MediaId? + if (flags & (1 << 0)) != 0, let webpageId = webpageId, webpageId != 0 { + webpageMediaId = MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId) + } + self = .image(id: MediaId(namespace: Namespaces.Media.CloudImage, id: photoId), caption: InstantPageCaption(apiCaption: caption), url: url, webpageId: webpageMediaId) + case let .pageBlockVideo(flags, videoId, caption): + self = .video(id: MediaId(namespace: Namespaces.Media.CloudFile, id: videoId), caption: InstantPageCaption(apiCaption: caption), autoplay: (flags & (1 << 0)) != 0, loop: (flags & (1 << 1)) != 0) + case let .pageBlockCover(cover): + self = .cover(InstantPageBlock(apiBlock: cover)) + case let .pageBlockEmbed(flags, url, html, posterPhotoId, w, h, caption): + var dimensions: CGSize? + if let w = w, let h = h { + dimensions = CGSize(width: CGFloat(w), height: CGFloat(h)) + } + self = .webEmbed(url: url, html: html, dimensions: dimensions, caption: InstantPageCaption(apiCaption: caption), stretchToWidth: (flags & (1 << 0)) != 0, allowScrolling: (flags & (1 << 3)) != 0, coverId: posterPhotoId.flatMap { MediaId(namespace: Namespaces.Media.CloudImage, id: $0) }) + case let .pageBlockEmbedPost(url, webpageId, authorPhotoId, author, date, blocks, caption): + self = .postEmbed(url: url, webpageId: webpageId == 0 ? nil : MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId), avatarId: authorPhotoId == 0 ? nil : MediaId(namespace: Namespaces.Media.CloudImage, id: authorPhotoId), author: author, date: date, blocks: blocks.map({ InstantPageBlock(apiBlock: $0) }), caption: InstantPageCaption(apiCaption: caption)) + case let .pageBlockCollage(items, caption): + self = .collage(items: items.map({ InstantPageBlock(apiBlock: $0) }), caption: InstantPageCaption(apiCaption: caption)) + case let .pageBlockSlideshow(items, caption): + self = .slideshow(items: items.map({ InstantPageBlock(apiBlock: $0) }), caption: InstantPageCaption(apiCaption: caption)) + case let .pageBlockChannel(channel: apiChat): + self = .channelBanner(parseTelegramGroupOrChannel(chat: apiChat) as? TelegramChannel) + case let .pageBlockAudio(audioId, caption): + self = .audio(id: MediaId(namespace: Namespaces.Media.CloudFile, id: audioId), caption: InstantPageCaption(apiCaption: caption)) + case let .pageBlockKicker(text): + self = .kicker(RichText(apiText: text)) + case let .pageBlockTable(flags, title, rows): + self = .table(title: RichText(apiText: title), rows: rows.map({ InstantPageTableRow(apiTableRow: $0) }), bordered: (flags & (1 << 0)) != 0, striped: (flags & (1 << 1)) != 0) + case let .pageBlockList(items): + self = .list(items: items.map({ InstantPageListItem(apiListItem: $0) }), ordered: false) + case let .pageBlockOrderedList(items): + self = .list(items: items.map({ InstantPageListItem(apiListOrderedItem: $0) }), ordered: true) + case let .pageBlockDetails(flags, blocks, title): + self = .details(title: RichText(apiText: title), blocks: blocks.map({ InstantPageBlock(apiBlock: $0) }), expanded: (flags & (1 << 0)) != 0) + case let .pageBlockRelatedArticles(title, articles): + self = .relatedArticles(title: RichText(apiText: title), articles: articles.map({ InstantPageRelatedArticle(apiRelatedArticle: $0) })) + case let .pageBlockMap(geo, zoom, w, h, caption): + switch geo { + case let .geoPoint(long, lat, _): + self = .map(latitude: lat, longitude: long, zoom: zoom, dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), caption: InstantPageCaption(apiCaption: caption)) + default: + self = .unsupported + } + } + } +} + +extension InstantPage { + convenience init(apiPage: Api.Page) { + let blocks: [Api.PageBlock] + let photos: [Api.Photo] + let files: [Api.Document] + let isComplete: Bool + let rtl: Bool + let url: String + switch apiPage { + case let .page(page): + url = page.url + blocks = page.blocks + photos = page.photos + files = page.documents + isComplete = (page.flags & (1 << 0)) == 0 + rtl = (page.flags & (1 << 1)) != 0 + } + var media: [MediaId: Media] = [:] + for photo in photos { + if let image = telegramMediaImageFromApiPhoto(photo), let id = image.id { + media[id] = image + } + } + for file in files { + if let file = telegramMediaFileFromApiDocument(file), let id = file.id { + media[id] = file + } + } + self.init(blocks: blocks.map({ InstantPageBlock(apiBlock: $0) }), media: media, isComplete: isComplete, rtl: rtl, url: url) + } +} diff --git a/submodules/TelegramCore/TelegramCore/InteractivePhoneFormatter.swift b/submodules/TelegramCore/TelegramCore/InteractivePhoneFormatter.swift new file mode 100644 index 0000000000..b7f613307d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InteractivePhoneFormatter.swift @@ -0,0 +1,15 @@ +import Foundation +import TelegramCorePrivateModule + +public final class InteractivePhoneFormatter { + private let formatter = NBAsYouTypeFormatter(regionCode: "US")! + + public init() { + } + + public func updateText(_ text: String) -> (String?, String) { + self.formatter.clear() + let string = self.formatter.inputString(text) + return (self.formatter.regionPrefix, string ?? "") + } +} diff --git a/submodules/TelegramCore/TelegramCore/InvitationLinks.swift b/submodules/TelegramCore/TelegramCore/InvitationLinks.swift new file mode 100644 index 0000000000..95b72efe06 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/InvitationLinks.swift @@ -0,0 +1,66 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + if let _ = peer as? TelegramChannel { + if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted { + return .complete() + } else { + return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer)) + |> retryRequest + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if let invitation = ExportedInvitation(apiExportedInvite: result) { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedChannelData { + return current.withUpdatedExportedInvitation(invitation) + } else { + return CachedChannelData().withUpdatedExportedInvitation(invitation) + } + }) + } + } + } + } + } else if let _ = peer as? TelegramGroup { + if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted { + return .complete() + } else { + return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer)) + |> retryRequest + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if let invitation = ExportedInvitation(apiExportedInvite: result) { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedGroupData { + return current.withUpdatedExportedInvitation(invitation) + } else { + return current + } + }) + } + } + } + } + } else { + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/JSON.swift b/submodules/TelegramCore/TelegramCore/JSON.swift new file mode 100644 index 0000000000..d9a365242c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/JSON.swift @@ -0,0 +1,509 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public indirect enum JSON: PostboxCoding, Equatable { + case null + case number(Double) + case string(String) + case bool(Bool) + case array([JSON]) + case dictionary([String: JSON]) + + private enum ValueType: Int32 { + case null = 0 + case number = 1 + case string = 2 + case bool = 3 + case array = 4 + case dictionary = 5 + } + + private init?(_ object: Any) { + if let object = object as? JSONValue { + self = object.jsonValue + } else if let dict = object as? [String: Any] { + var values: [String: JSON] = [:] + for (key, value) in dict { + if let v = JSON(value) { + values[key] = v + } else { + return nil + } + } + self = .dictionary(values) + } else if let array = object as? [Any] { + var values: [JSON] = [] + for value in array { + if let v = JSON(value) { + values.append(v) + } else { + return nil + } + } + self = .array(values) + } + else if let value = object as? String { + self = .string(value) + } else if let value = object as? Int { + self = .number(Double(value)) + } else { + return nil + } + } + + public init?(data: Data) { + if let object = try? JSONSerialization.jsonObject(with: data, options: []) { + self.init(object) + } else { + return nil + } + } + + public init?(string: String) { + if let data = string.data(using: .utf8) { + self.init(data: data) + } else { + return nil + } + } + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case ValueType.null.rawValue: + self = .null + case ValueType.number.rawValue: + self = .number(decoder.decodeDoubleForKey("v", orElse: 0.0)) + case ValueType.string.rawValue: + self = .string(decoder.decodeStringForKey("v", orElse: "")) + case ValueType.bool.rawValue: + self = .bool(decoder.decodeBoolForKey("v", orElse: false)) + case ValueType.array.rawValue: + self = .array(decoder.decodeObjectArrayForKey("v")) + case ValueType.dictionary.rawValue: + self = .dictionary(decoder.decodeObjectDictionaryForKey("v", keyDecoder: { $0.decodeStringForKey("k", orElse: "") + }, valueDecoder: { JSON(decoder: $0) })) + default: + self = .null + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .null: + encoder.encodeInt32(ValueType.null.rawValue, forKey: "r") + case let .number(value): + encoder.encodeInt32(ValueType.number.rawValue, forKey: "r") + encoder.encodeDouble(value, forKey: "v") + case let .string(value): + encoder.encodeInt32(ValueType.string.rawValue, forKey: "r") + encoder.encodeString(value, forKey: "v") + case let .bool(value): + encoder.encodeInt32(ValueType.bool.rawValue, forKey: "r") + encoder.encodeBool(value, forKey: "v") + case let .array(value): + encoder.encodeInt32(ValueType.array.rawValue, forKey: "r") + encoder.encodeObjectArray(value, forKey: "v") + case let .dictionary(value): + encoder.encodeInt32(ValueType.dictionary.rawValue, forKey: "r") + encoder.encodeObjectDictionary(value, forKey: "v") { key, encoder in + encoder.encodeString(key, forKey: "k") + } + } + } + + public static func ==(lhs: JSON, rhs: JSON) -> Bool { + switch lhs { + case .null: + if case .null = rhs { + return true + } else { + return false + } + case let .number(value): + if case .number(value) = rhs { + return true + } else { + return false + } + case let .string(value): + if case .string(value) = rhs { + return true + } else { + return false + } + case let .bool(value): + if case .bool(value) = rhs { + return true + } else { + return false + } + case let .array(value): + if case .array(value) = rhs { + return true + } else { + return false + } + case let .dictionary(value): + if case .dictionary(value) = rhs { + return true + } else { + return false + } + } + } + + public enum Index: Comparable { + case array(Int) + case dictionary(DictionaryIndex) + case null + + static public func ==(lhs: Index, rhs: Index) -> Bool { + switch (lhs, rhs) { + case let (.array(lhs), .array(rhs)): + return lhs == rhs + case let (.dictionary(lhs), .dictionary(rhs)): + return lhs == rhs + case (.null, .null): + return true + default: + return false + } + } + + static public func <(lhs: Index, rhs: Index) -> Bool { + switch (lhs, rhs) { + case let (.array(lhs), .array(rhs)): + return lhs < rhs + case let (.dictionary(lhs), .dictionary(rhs)): + return lhs < rhs + default: + return false + } + } + } +} + +extension JSON: Collection { + public var startIndex: Index { + switch self { + case let .array(value): + return .array(value.startIndex) + case let .dictionary(value): + return .dictionary(value.startIndex) + default: + return .null + } + } + + public var endIndex: Index { + switch self { + case let .array(value): + return .array(value.endIndex) + case let .dictionary(value): + return .dictionary(value.endIndex) + default: + return .null + } + } + + public func index(after i: Index) -> Index { + switch (i, self) { + case let (.array(index), .array(value)): + return .array(value.index(after: index)) + case let (.dictionary(index), .dictionary(value)): + return .dictionary(value.index(after: index)) + default: + return .null + } + } + + public subscript (position: Index) -> (String, JSON) { + switch (position, self) { + case let (.array(index), .array(value)): + return (String(index), value[index]) + case let (.dictionary(index), .dictionary(value)): + let (key, value) = value[index] + return (key, value) + default: + return ("", .null) + } + } +} + +public enum JSONKey { + case index(Int) + case key(String) +} + +public protocol JSONSubscriptType { + var jsonKey: JSONKey { get } +} + +extension Int: JSONSubscriptType { + public var jsonKey: JSONKey { + return .index(self) + } +} + +extension String: JSONSubscriptType { + public var jsonKey: JSONKey { + return .key(self) + } +} + +extension JSON { + fileprivate var value: JSONElement { + get { + switch self { + case .null: + return 0 + case let .number(value): + return value + case let .string(value): + return value + case let .bool(value): + return value + case let .array(values): + var array: [JSONElement] = [] + for value in values { + array.append(value.value) + } + return array + case let .dictionary(values): + var dictionary: [String: JSONElement] = [:] + for (key, value) in values { + dictionary[key] = value.value + } + return dictionary + } + } + } +} + +extension JSON { + public subscript(key: JSONSubscriptType) -> JSONElement? { + get { + switch (key.jsonKey, self) { + case let (.index(index), .array(value)): + if value.indices.contains(index) { + return value[index].value + } else { + return nil + } + case let (.key(key), .dictionary(value)): + if let value = value[key] { + return value.value + } else { + return nil + } + default: + return nil + } + } + } +} + +extension JSON: ExpressibleByDictionaryLiteral { + public init(dictionaryLiteral elements: (String, Any)...) { + self = .dictionary(elements.reduce([String: JSON]()) { (dictionary, element) in + var dictionary = dictionary + if let value = JSON(element.1) { + dictionary[element.0] = value + } + return dictionary + }) + } +} + +extension JSON: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: Any...) { + self = .array(elements.compactMap { JSON($0) }) + } +} + +public protocol JSONElement {} +private protocol JSONValue { + var jsonValue: JSON { get } +} + +extension Int: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension Int8: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension Int16: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension Int32: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension Int64: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension UInt: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension UInt8: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension UInt16: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension UInt32: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension UInt64: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(Double(self)) + } +} + +extension Double: JSONElement, JSONValue { + var jsonValue: JSON { + return .number(self) + } +} + +extension String: JSONElement, JSONValue { + var jsonValue: JSON { + return .string(self) + } +} + +extension Bool: JSONElement, JSONValue { + var jsonValue: JSON { + return .bool(self) + } +} + +extension Array: JSONElement where Element == JSONElement { +} + +extension Array: JSONValue where Element == JSONValue { + var jsonValue: JSON { + return .array(self.map { $0.jsonValue }) + } +} + +extension Dictionary: JSONElement where Key == String, Value == JSONElement { +} + +extension Dictionary: JSONValue where Key == String, Value == JSONValue { + var jsonValue: JSON { + return .dictionary(self.mapValues { $0.jsonValue }) + } +} + +private extension Bool { + init(apiBool: Api.Bool) { + switch apiBool { + case .boolTrue: + self.init(true) + case .boolFalse: + self.init(false) + } + } + + var apiBool: Api.Bool { + if self { + return .boolTrue + } else { + return .boolFalse + } + } +} + +extension JSON { + private init?(apiJson: Api.JSONValue, root: Bool) { + switch (apiJson, root) { + case (.jsonNull, false): + self = .null + case let (.jsonNumber(value), false): + self = .number(value) + case let (.jsonString(value), false): + self = .string(value) + case let (.jsonBool(value), false): + self = .bool(Bool(apiBool: value)) + case let (.jsonArray(value), _): + self = .array(value.compactMap { JSON(apiJson: $0, root: false) }) + case let (.jsonObject(value), _): + self = .dictionary(value.reduce([String: JSON]()) { dictionary, value in + var dictionary = dictionary + switch value { + case let .jsonObjectValue(key, value): + if let value = JSON(apiJson: value, root: false) { + dictionary[key] = value + } + } + return dictionary + }) + default: + return nil + } + } + + init?(apiJson: Api.JSONValue) { + self.init(apiJson: apiJson, root: true) + } +} + +private func apiJson(_ json: JSON, root: Bool) -> Api.JSONValue? { + switch (json, root) { + case (.null, false): + return .jsonNull + case let (.number(value), false): + return .jsonNumber(value: value) + case let (.string(value), false): + return .jsonString(value: value) + case let (.bool(value), false): + return .jsonBool(value: value.apiBool) + case let (.array(value), _): + return .jsonArray(value: value.compactMap { apiJson($0, root: false) }) + case let (.dictionary(value), _): + return .jsonObject(value: value.reduce([Api.JSONObjectValue]()) { objectValues, keyAndValue in + var objectValues = objectValues + if let value = apiJson(keyAndValue.value, root: false) { + objectValues.append(.jsonObjectValue(key: keyAndValue.key, value: value)) + } + return objectValues + }) + default: + return nil + } +} + +func apiJson(_ json: JSON) -> Api.JSONValue? { + return apiJson(json, root: true) +} diff --git a/submodules/TelegramCore/TelegramCore/JoinChannel.swift b/submodules/TelegramCore/TelegramCore/JoinChannel.swift new file mode 100644 index 0000000000..253165666c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/JoinChannel.swift @@ -0,0 +1,67 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum JoinChannelError { + case generic +} + +public func joinChannel(account: Account, peerId: PeerId) -> Signal { + return account.postbox.loadedPeerWithId(peerId) + |> take(1) + |> introduceError(JoinChannelError.self) + |> mapToSignal { peer -> Signal in + if let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.joinChannel(channel: inputChannel)) + |> mapError { _ -> JoinChannelError in + return .generic + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + + return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, userId: .inputUserSelf)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .fail(.generic) + } + return account.postbox.transaction { transaction -> RenderedChannelParticipant? in + var peers: [PeerId: Peer] = [:] + var presences: [PeerId: PeerPresence] = [:] + guard let peer = transaction.getPeer(account.peerId) else { + return nil + } + peers[account.peerId] = peer + if let presence = transaction.getPeerPresence(peerId: account.peerId) { + presences[account.peerId] = presence + } + let updatedParticipant: ChannelParticipant + switch result { + case let .channelParticipant(participant, _): + updatedParticipant = ChannelParticipant(apiParticipant: participant) + } + if case let .member(_, _, maybeAdminInfo, _) = updatedParticipant { + if let adminInfo = maybeAdminInfo { + if let peer = transaction.getPeer(adminInfo.promotedBy) { + peers[peer.id] = peer + } + } + } + return RenderedChannelParticipant(participant: updatedParticipant, peer: peer, peers: peers, presences: presences) + } + |> introduceError(JoinChannelError.self) + } + } + } else { + return .fail(.generic) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/JoinLink.swift b/submodules/TelegramCore/TelegramCore/JoinLink.swift new file mode 100644 index 0000000000..aec3b91426 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/JoinLink.swift @@ -0,0 +1,87 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func apiUpdatesGroups(_ updates: Api.Updates) -> [Api.Chat] { + switch updates { + case let .updates( _, _, chats, _, _): + return chats + case let .updatesCombined(_, _, chats, _, _, _): + return chats + default: + return [] + } +} + +public enum ExternalJoiningChatState { + case invite(title: String, photoRepresentation: TelegramMediaImageRepresentation?, participantsCount: Int32, participants: [Peer]?) + case alreadyJoined(PeerId) + case invalidHash +} + +public func joinChatInteractively(with hash: String, account: Account) -> Signal { + return account.network.request(Api.functions.messages.importChatInvite(hash: hash)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + if let peerId = apiUpdatesGroups(updates).first?.peerId { + return account.postbox.multiplePeersView([peerId]) + |> filter { view in + return view.peers[peerId] != nil + } + |> take(1) + |> map { _ in + return peerId + } + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil)) + } + return .single(nil) + } else { + return .single(nil) + } + } +} + +public func joinLinkInformation(_ hash: String, account: Account) -> Signal { + return account.network.request(Api.functions.messages.checkChatInvite(hash: hash)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { (result) -> Signal in + if let result = result { + switch result { + case let .chatInvite(invite): + let photo = telegramMediaImageFromApiPhoto(invite.photo).flatMap({ smallestImageRepresentation($0.representations) }) + return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)}))) + case let .chatInviteAlready(chat: chat): + if let peer = parseTelegramGroupOrChannel(chat: chat) { + return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in + updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in + return updated + }) + + return .alreadyJoined(peer.id) + }) + } + return .single(.invalidHash) + } + } else { + return .single(.invalidHash) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/LimitsConfiguration.swift b/submodules/TelegramCore/TelegramCore/LimitsConfiguration.swift new file mode 100644 index 0000000000..dc95b68f0c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LimitsConfiguration.swift @@ -0,0 +1,93 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct LimitsConfiguration: Equatable, PreferencesEntry { + public static let timeIntervalForever: Int32 = 0x7fffffff + + public var maxPinnedChatCount: Int32 + public var maxArchivedPinnedChatCount: Int32 + public var maxGroupMemberCount: Int32 + public var maxSupergroupMemberCount: Int32 + public var maxMessageForwardBatchSize: Int32 + public var maxSavedGifCount: Int32 + public var maxRecentStickerCount: Int32 + public var maxMessageEditingInterval: Int32 + public var maxMediaCaptionLength: Int32 + public var canRemoveIncomingMessagesInPrivateChats: Bool + public var maxMessageRevokeInterval: Int32 + public var maxMessageRevokeIntervalInPrivateChats: Int32 + + public static var defaultValue: LimitsConfiguration { + return LimitsConfiguration(maxPinnedChatCount: 5, maxArchivedPinnedChatCount: 20, maxGroupMemberCount: 200, maxSupergroupMemberCount: 200000, maxMessageForwardBatchSize: 50, maxSavedGifCount: 200, maxRecentStickerCount: 20, maxMessageEditingInterval: 2 * 24 * 60 * 60, maxMediaCaptionLength: 1000, canRemoveIncomingMessagesInPrivateChats: false, maxMessageRevokeInterval: 2 * 24 * 60 * 60, maxMessageRevokeIntervalInPrivateChats: 2 * 24 * 60 * 60) + } + + init(maxPinnedChatCount: Int32, maxArchivedPinnedChatCount: Int32, maxGroupMemberCount: Int32, maxSupergroupMemberCount: Int32, maxMessageForwardBatchSize: Int32, maxSavedGifCount: Int32, maxRecentStickerCount: Int32, maxMessageEditingInterval: Int32, maxMediaCaptionLength: Int32, canRemoveIncomingMessagesInPrivateChats: Bool, maxMessageRevokeInterval: Int32, maxMessageRevokeIntervalInPrivateChats: Int32) { + self.maxPinnedChatCount = maxPinnedChatCount + self.maxArchivedPinnedChatCount = maxArchivedPinnedChatCount + self.maxGroupMemberCount = maxGroupMemberCount + self.maxSupergroupMemberCount = maxSupergroupMemberCount + self.maxMessageForwardBatchSize = maxMessageForwardBatchSize + self.maxSavedGifCount = maxSavedGifCount + self.maxRecentStickerCount = maxRecentStickerCount + self.maxMessageEditingInterval = maxMessageEditingInterval + self.maxMediaCaptionLength = maxMediaCaptionLength + self.canRemoveIncomingMessagesInPrivateChats = canRemoveIncomingMessagesInPrivateChats + self.maxMessageRevokeInterval = maxMessageRevokeInterval + self.maxMessageRevokeIntervalInPrivateChats = maxMessageRevokeIntervalInPrivateChats + } + + public init(decoder: PostboxDecoder) { + self.maxPinnedChatCount = decoder.decodeInt32ForKey("maxPinnedChatCount", orElse: 5) + self.maxArchivedPinnedChatCount = decoder.decodeInt32ForKey("maxArchivedPinnedChatCount", orElse: 20) + self.maxGroupMemberCount = decoder.decodeInt32ForKey("maxGroupMemberCount", orElse: 200) + self.maxSupergroupMemberCount = decoder.decodeInt32ForKey("maxSupergroupMemberCount", orElse: 5000) + self.maxMessageForwardBatchSize = decoder.decodeInt32ForKey("maxMessageForwardBatchSize", orElse: 50) + self.maxSavedGifCount = decoder.decodeInt32ForKey("maxSavedGifCount", orElse: 200) + self.maxRecentStickerCount = decoder.decodeInt32ForKey("maxRecentStickerCount", orElse: 20) + self.maxMessageEditingInterval = decoder.decodeInt32ForKey("maxMessageEditingInterval", orElse: 2 * 24 * 60 * 60) + self.maxMediaCaptionLength = decoder.decodeInt32ForKey("maxMediaCaptionLength", orElse: 1000) + self.canRemoveIncomingMessagesInPrivateChats = decoder.decodeInt32ForKey("canRemoveIncomingMessagesInPrivateChats", orElse: 0) != 0 + self.maxMessageRevokeInterval = decoder.decodeInt32ForKey("maxMessageRevokeInterval", orElse: 2 * 24 * 60 * 60) + self.maxMessageRevokeIntervalInPrivateChats = decoder.decodeInt32ForKey("maxMessageRevokeIntervalInPrivateChats", orElse: 2 * 24 * 60 * 60) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.maxPinnedChatCount, forKey: "maxPinnedChatCount") + encoder.encodeInt32(self.maxArchivedPinnedChatCount, forKey: "maxArchivedPinnedChatCount") + encoder.encodeInt32(self.maxGroupMemberCount, forKey: "maxGroupMemberCount") + encoder.encodeInt32(self.maxSupergroupMemberCount, forKey: "maxSupergroupMemberCount") + encoder.encodeInt32(self.maxMessageForwardBatchSize, forKey: "maxMessageForwardBatchSize") + encoder.encodeInt32(self.maxSavedGifCount, forKey: "maxSavedGifCount") + encoder.encodeInt32(self.maxRecentStickerCount, forKey: "maxRecentStickerCount") + encoder.encodeInt32(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval") + encoder.encodeInt32(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength") + encoder.encodeInt32(self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0, forKey: "canRemoveIncomingMessagesInPrivateChats") + encoder.encodeInt32(self.maxMessageRevokeInterval, forKey: "maxMessageRevokeInterval") + encoder.encodeInt32(self.maxMessageRevokeIntervalInPrivateChats, forKey: "maxMessageRevokeIntervalInPrivateChats") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? LimitsConfiguration else { + return false + } + return self == to + } +} + +public func currentLimitsConfiguration(transaction: Transaction) -> LimitsConfiguration { + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration { + return entry + } else { + return LimitsConfiguration.defaultValue + } +} + +func updateLimitsConfiguration(transaction: Transaction, configuration: LimitsConfiguration) { + if !currentLimitsConfiguration(transaction: transaction).isEqual(to: configuration) { + transaction.setPreferencesEntry(key: PreferencesKeys.limitsConfiguration, value: configuration) + } +} diff --git a/submodules/TelegramCore/TelegramCore/LoadMessagesIfNecessary.swift b/submodules/TelegramCore/TelegramCore/LoadMessagesIfNecessary.swift new file mode 100644 index 0000000000..4b9cf9d510 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoadMessagesIfNecessary.swift @@ -0,0 +1,133 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum GetMessagesStrategy { + case local + case cloud +} + +public func getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Postbox, network: Network, accountPeerId: PeerId, strategy: GetMessagesStrategy = .cloud) -> Signal <[Message], NoError> { + let postboxSignal = postbox.transaction { transaction -> ([Message], Set, SimpleDictionary) in + + var ids = messageIds + + if let cachedData = transaction.getPeerCachedData(peerId: messageIds[0].peerId) as? CachedChannelData { + if let minAvailableMessageId = cachedData.minAvailableMessageId { + ids = ids.filter({$0 < minAvailableMessageId}) + } + } + + var messages:[Message] = [] + var missingMessageIds:Set = Set() + var supportPeers:SimpleDictionary = SimpleDictionary() + for messageId in ids { + if let message = transaction.getMessage(messageId) { + messages.append(message) + } else { + missingMessageIds.insert(messageId) + if let peer = transaction.getPeer(messageId.peerId) { + supportPeers[messageId.peerId] = peer + } + } + } + return (messages, missingMessageIds, supportPeers) + } + + if strategy == .cloud { + return postboxSignal + |> mapToSignal { (existMessages, missingMessageIds, supportPeers) in + + var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] + for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { + if let peer = supportPeers[peerId] { + var signal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + signal = network.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) }))) + } + } + if let signal = signal { + signals.append(signal |> map { result in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, messages, chats, users): + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + }) + } + } + } + + return combineLatest(signals) |> mapToSignal { results -> Signal<[Message], NoError> in + return postbox.transaction { transaction -> [Message] in + + for (messages, chats, users) in results { + if !messages.isEmpty { + var storeMessages: [StoreMessage] = [] + + for message in messages { + if let message = StoreMessage(apiMessage: message) { + storeMessages.append(message) + } + } + _ = transaction.addMessages(storeMessages, location: .Random) + } + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + } + var loadedMessages:[Message] = [] + for messageId in missingMessageIds { + if let message = transaction.getMessage(messageId) { + loadedMessages.append(message) + } + } + + return existMessages + loadedMessages + } + } + + } + } else { + return postboxSignal |> map {$0.0} + } + +} diff --git a/submodules/TelegramCore/TelegramCore/LoadedPeer.swift b/submodules/TelegramCore/TelegramCore/LoadedPeer.swift new file mode 100644 index 0000000000..96bfba6734 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoadedPeer.swift @@ -0,0 +1,76 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func actualizedPeer(postbox: Postbox, network: Network, peer: Peer) -> Signal { + return postbox.transaction { transaction -> Signal in + var signal: Signal + var actualizeChannel: Api.InputChannel? + if let currentPeer = transaction.getPeer(peer.id) { + signal = .single(currentPeer) + if let currentPeer = currentPeer as? TelegramChannel { + switch currentPeer.participationStatus { + case .left, .kicked: + actualizeChannel = apiInputChannel(currentPeer) + default: + break + } + } + } else { + signal = .single(peer) + if let peer = peer as? TelegramChannel { + actualizeChannel = apiInputChannel(peer) + } + } + if let actualizeChannel = actualizeChannel { + let remote = network.request(Api.functions.channels.getChannels(id: [actualizeChannel])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + var remotePeer: Peer? + if let result = result { + let chats: [Api.Chat] + switch result { + case let .chats(apiChats): + chats = apiChats + case let .chatsSlice(_, apiChats): + chats = apiChats + } + for chat in chats { + if let parsedPeer = parseTelegramGroupOrChannel(chat: chat), parsedPeer.id == peer.id { + remotePeer = parsedPeer + } + } + } + if let remotePeer = remotePeer { + return postbox.transaction { transaction -> Peer in + updatePeers(transaction: transaction, peers: [remotePeer], update: { _, updated in + return updated + }) + return remotePeer + } + } else { + return .complete() + } + } + signal = signal |> then(remote) + } + + let updatedView: Signal = postbox.combinedView(keys: [.peer(peerId: peer.id, components: .all)]) + |> mapToSignal { view -> Signal in + if let peerView = view.views[.peer(peerId: peer.id, components: .all)] as? PeerView, let peer = peerView.peers[peerView.peerId] { + return .single(peer) + } + return .complete() + } + + return (signal |> then(updatedView)) |> distinctUntilChanged(isEqual: { $0.isEqual($1) }) + } |> switchToLatest +} + diff --git a/submodules/TelegramCore/TelegramCore/LoadedPeerFromMessage.swift b/submodules/TelegramCore/TelegramCore/LoadedPeerFromMessage.swift new file mode 100644 index 0000000000..169f4f702c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoadedPeerFromMessage.swift @@ -0,0 +1,79 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: MessageId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if let user = peer as? TelegramUser { + if user.accessHash != 0 { + return .single(user) + } else { + let messageSignal: Signal? + if messageId.peerId.namespace == Namespaces.Peer.CloudUser || messageId.peerId.namespace == Namespaces.Peer.CloudGroup { + messageSignal = account.network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + } else if messageId.peerId.namespace == Namespaces.Peer.CloudChannel, let channelPeer = transaction.getPeer(messageId.peerId), let inputChannel = apiInputChannel(channelPeer) { + messageSignal = account.network.request(Api.functions.channels.getMessages(channel: inputChannel, id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + messageSignal = nil + } + + if let messageSignal = messageSignal { + return messageSignal |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Peer? in + if let result = result { + let apiUsers: [Api.User] + switch result { + case let .messages(_, _, users): + apiUsers = users + case let .messagesSlice(_, _, _, _, _, users): + apiUsers = users + case let .channelMessages(_, _, _, _, _, users): + apiUsers = users + case .messagesNotModified: + apiUsers = [] + } + + for user in apiUsers { + let telegramUser = TelegramUser(user: user) + if telegramUser.id == peerId && telegramUser.accessHash != 0 { + if let presence = TelegramUserPresence(apiUser: user) { + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: [telegramUser.id: presence]) + } + + updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in + return updated + }) + + return telegramUser + } + } + } + return nil + } + } + } else { + return .single(nil) + } + } + } else { + return .single(peer) + } + } else { + return .single(nil) + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/LoadedStickerPack.swift b/submodules/TelegramCore/TelegramCore/LoadedStickerPack.swift new file mode 100644 index 0000000000..32035393d2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoadedStickerPack.swift @@ -0,0 +1,108 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +extension StickerPackReference { + init(_ stickerPackInfo: StickerPackCollectionInfo) { + self = .id(id: stickerPackInfo.id.id, accessHash: stickerPackInfo.accessHash) + } + + var apiInputStickerSet: Api.InputStickerSet { + switch self { + case let .id(id, accessHash): + return .inputStickerSetID(id: id, accessHash: accessHash) + case let .name(name): + return .inputStickerSetShortName(shortName: name) + } + } +} + +public enum LoadedStickerPack { + case fetching + case none + case result(info: StickerPackCollectionInfo, items: [ItemCollectionItem], installed: Bool) +} + +func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem])?, NoError> { + return network.request(Api.functions.messages.getStickerSet(stickerset: reference.apiInputStickerSet)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem])?, NoError> in + guard let result = result else { + return .single(nil) + } + + let info: StickerPackCollectionInfo + var items: [ItemCollectionItem] = [] + switch result { + case let .stickerSet(set, packs, documents): + let namespace: ItemCollectionId.Namespace + switch set { + case let .stickerSet(flags, _, _, _, _, _, _, _, _, _): + if (flags & (1 << 3)) != 0 { + namespace = Namespaces.ItemCollection.CloudMaskPacks + } else { + namespace = Namespaces.ItemCollection.CloudStickerPacks + } + } + info = StickerPackCollectionInfo(apiSet: set, namespace: namespace) + var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + let key = ValueBoxKey(text).toMemoryBuffer() + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if indexKeysByFile[mediaId] == nil { + indexKeysByFile[mediaId] = [key] + } else { + indexKeysByFile[mediaId]!.append(key) + } + } + } + } + + for apiDocument in documents { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + let fileIndexKeys: [MemoryBuffer] + if let indexKeys = indexKeysByFile[id] { + fileIndexKeys = indexKeys + } else { + fileIndexKeys = [] + } + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys)) + } + } + } + + return postbox.transaction { transaction -> (StickerPackCollectionInfo, [ItemCollectionItem])? in + if transaction.getItemCollectionInfo(collectionId: info.id) != nil { + transaction.replaceItemCollectionItems(collectionId: info.id, items: items) + } + cacheStickerPack(transaction: transaction, info: info, items: items) + + return (info, items) + } + } +} + +public func loadedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceActualized: Bool) -> Signal { + return cachedStickerPack(postbox: postbox, network: network, reference: reference, forceRemote: forceActualized) + |> map { result -> LoadedStickerPack in + switch result { + case .none: + return .none + case .fetching: + return .fetching + case let .result(info, items, installed): + return .result(info: info, items: items, installed: installed) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Localization.swift b/submodules/TelegramCore/TelegramCore/Localization.swift new file mode 100644 index 0000000000..2cc395e0e7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Localization.swift @@ -0,0 +1,262 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum LocalizationEntry: Equatable { + case string(key: String, value: String) + case pluralizedString(key: String, zero: String?, one: String?, two: String?, few: String?, many: String?, other: String) + + public var key: String { + switch self { + case let .string(key, _): + return key + case let .pluralizedString(key, _, _, _, _, _, _): + return key + } + } + + public static func ==(lhs: LocalizationEntry, rhs: LocalizationEntry) -> Bool { + switch lhs { + case let .string(lhsKey, lhsValue): + if case let .string(rhsKey, rhsValue) = rhs, lhsKey == rhsKey, lhsValue == rhsValue { + return true + } else { + return false + } + case let .pluralizedString(lhsKey, lhsZero, lhsOne, lhsTwo, lhsFew, lhsMany, lhsOther): + if case let .pluralizedString(rhsKey, rhsZero, rhsOne, rhsTwo, rhsFew, rhsMany, rhsOther) = rhs { + if lhsKey != rhsKey { + return false + } + if lhsZero != rhsZero { + return false + } + if lhsOne != rhsOne { + return false + } + if lhsTwo != rhsTwo { + return false + } + if lhsFew != rhsFew { + return false + } + if lhsMany != rhsMany { + return false + } + if lhsOther != rhsOther { + return false + } + return true + } else { + return false + } + } + } +} + +private struct LocalizationEntryFlags: OptionSet { + var rawValue: Int8 + + init(rawValue: Int8) { + self.rawValue = rawValue + } + + init() { + self.rawValue = 0 + } + + static let pluralized = LocalizationEntryFlags(rawValue: (1 << 0)) + static let hasZero = LocalizationEntryFlags(rawValue: (1 << 1)) + static let hasOne = LocalizationEntryFlags(rawValue: (1 << 2)) + static let hasTwo = LocalizationEntryFlags(rawValue: (1 << 3)) + static let hasFew = LocalizationEntryFlags(rawValue: (1 << 4)) + static let hasMany = LocalizationEntryFlags(rawValue: (1 << 5)) +} + +private func writeString(_ buffer: WriteBuffer, _ string: String) { + if let data = string.data(using: .utf8) { + var length: Int32 = Int32(data.count) + buffer.write(&length, offset: 0, length: 4) + buffer.write(data) + } else { + var length: Int32 = 0 + buffer.write(&length, offset: 0, length: 4) + } +} + +public final class Localization: PostboxCoding, Equatable { + public let version: Int32 + public let entries: [LocalizationEntry] + + public init(version: Int32, entries: [LocalizationEntry]) { + self.version = version + self.entries = entries + } + + public init(decoder: PostboxDecoder) { + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + let count = decoder.decodeInt32ForKey("c", orElse: 0) + var entries: [LocalizationEntry] = [] + if let data = decoder.decodeBytesForKey("d") { + for _ in 0 ..< count { + var flagsValue: Int8 = 0 + data.read(&flagsValue, offset: 0, length: 1) + let flags = LocalizationEntryFlags(rawValue: flagsValue) + + var length: Int32 = 0 + data.read(&length, offset: 0, length: 4) + + let keyData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let key = String(data: keyData, encoding: .utf8) + data.skip(Int(length)) + + if flags.contains(.pluralized) { + var zero: String? + var one: String? + var two: String? + var few: String? + var many: String? + var other: String? + + if flags.contains(.hasZero) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + zero = value + } + + if flags.contains(.hasOne) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + one = value + } + + if flags.contains(.hasTwo) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + two = value + } + + if flags.contains(.hasFew) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + few = value + } + + if flags.contains(.hasMany) { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + many = value + } + + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + other = value + + if let key = key, let other = other { + entries.append(.pluralizedString(key: key, zero: zero, one: one, two: two, few: few, many: many, other: other)) + } + } else { + length = 0 + data.read(&length, offset: 0, length: 4) + let valueData = Data(bytes: data.memory.advanced(by: data.offset), count: Int(length)) + let value = String(data: valueData, encoding: .utf8) + data.skip(Int(length)) + + if let key = key, let value = value { + entries.append(.string(key: key, value: value)) + } + } + } + } + self.entries = entries + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.version, forKey: "v") + encoder.encodeInt32(Int32(self.entries.count), forKey: "c") + + let buffer = WriteBuffer() + for entry in self.entries { + var flags: LocalizationEntryFlags = [] + switch entry { + case .string: + flags = [] + case let .pluralizedString(_, zero, one, two, few, many, _): + flags.insert(.pluralized) + if zero != nil { + flags.insert(.hasZero) + } + if one != nil { + flags.insert(.hasOne) + } + if two != nil { + flags.insert(.hasTwo) + } + if few != nil { + flags.insert(.hasFew) + } + if many != nil { + flags.insert(.hasMany) + } + } + var flagsValue: Int8 = flags.rawValue + buffer.write(&flagsValue, offset: 0, length: 1) + + switch entry { + case let .string(key, value): + writeString(buffer, key) + writeString(buffer, value) + case let .pluralizedString(key, zero, one, two, few, many, other): + writeString(buffer, key) + if let zero = zero { + writeString(buffer, zero) + } + if let one = one { + writeString(buffer, one) + } + if let two = two { + writeString(buffer, two) + } + if let few = few { + writeString(buffer, few) + } + if let many = many { + writeString(buffer, many) + } + writeString(buffer, other) + } + } + encoder.encodeBytes(buffer, forKey: "d") + } + + public static func ==(lhs: Localization, rhs: Localization) -> Bool { + if lhs === rhs { + return true + } + if lhs.entries == rhs.entries { + return true + } + return false + } +} diff --git a/submodules/TelegramCore/TelegramCore/LocalizationInfo.swift b/submodules/TelegramCore/TelegramCore/LocalizationInfo.swift new file mode 100644 index 0000000000..7f40c85ea0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LocalizationInfo.swift @@ -0,0 +1,84 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct LocalizationInfo: PostboxCoding, Equatable { + public let languageCode: String + public let baseLanguageCode: String? + public let customPluralizationCode: String? + public let title: String + public let localizedTitle: String + public let isOfficial: Bool + public let totalStringCount: Int32 + public let translatedStringCount: Int32 + public let platformUrl: String + + public init(languageCode: String, baseLanguageCode: String?, customPluralizationCode: String?, title: String, localizedTitle: String, isOfficial: Bool, totalStringCount: Int32, translatedStringCount: Int32, platformUrl: String) { + self.languageCode = languageCode + self.baseLanguageCode = baseLanguageCode + self.customPluralizationCode = customPluralizationCode + self.title = title + self.localizedTitle = localizedTitle + self.isOfficial = isOfficial + self.totalStringCount = totalStringCount + self.translatedStringCount = translatedStringCount + self.platformUrl = platformUrl + } + + public init(decoder: PostboxDecoder) { + self.languageCode = decoder.decodeStringForKey("lc", orElse: "") + self.baseLanguageCode = decoder.decodeOptionalStringForKey("nlc") + self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpc") + self.title = decoder.decodeStringForKey("t", orElse: "") + self.localizedTitle = decoder.decodeStringForKey("lt", orElse: "") + self.isOfficial = decoder.decodeInt32ForKey("of", orElse: 0) != 0 + self.totalStringCount = decoder.decodeInt32ForKey("tsc", orElse: 0) + self.translatedStringCount = decoder.decodeInt32ForKey("lsc", orElse: 0) + self.platformUrl = decoder.decodeStringForKey("platformUrl", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.languageCode, forKey: "lc") + if let baseLanguageCode = self.baseLanguageCode { + encoder.encodeString(baseLanguageCode, forKey: "nlc") + } else { + encoder.encodeNil(forKey: "nlc") + } + if let customPluralizationCode = self.customPluralizationCode { + encoder.encodeString(customPluralizationCode, forKey: "cpc") + } else { + encoder.encodeNil(forKey: "cpc") + } + encoder.encodeString(self.title, forKey: "t") + encoder.encodeString(self.localizedTitle, forKey: "lt") + encoder.encodeInt32(self.isOfficial ? 1 : 0, forKey: "of") + encoder.encodeInt32(self.totalStringCount, forKey: "tsc") + encoder.encodeInt32(self.translatedStringCount, forKey: "lsc") + encoder.encodeString(self.platformUrl, forKey: "platformUrl") + } +} + +extension LocalizationInfo { + init(apiLanguage: Api.LangPackLanguage) { + switch apiLanguage { + case let .langPackLanguage(language): + self.init(languageCode: language.langCode, baseLanguageCode: language.baseLangCode, customPluralizationCode: language.pluralCode, title: language.name, localizedTitle: language.nativeName, isOfficial: (language.flags & (1 << 0)) != 0, totalStringCount: language.stringsCount, translatedStringCount: language.translatedCount, platformUrl: language.translationsUrl) + } + } +} + +public final class SuggestedLocalizationInfo { + public let languageCode: String + public let extractedEntries: [LocalizationEntry] + + public let availableLocalizations: [LocalizationInfo] + + init(languageCode: String, extractedEntries: [LocalizationEntry], availableLocalizations: [LocalizationInfo]) { + self.languageCode = languageCode + self.extractedEntries = extractedEntries + self.availableLocalizations = availableLocalizations + } +} diff --git a/submodules/TelegramCore/TelegramCore/LocalizationListState.swift b/submodules/TelegramCore/TelegramCore/LocalizationListState.swift new file mode 100644 index 0000000000..bfbb48c39f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LocalizationListState.swift @@ -0,0 +1,102 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public struct LocalizationListState: PreferencesEntry, Equatable { + public var availableOfficialLocalizations: [LocalizationInfo] + public var availableSavedLocalizations: [LocalizationInfo] + + public static var defaultSettings: LocalizationListState { + return LocalizationListState(availableOfficialLocalizations: [], availableSavedLocalizations: []) + } + + public init(availableOfficialLocalizations: [LocalizationInfo], availableSavedLocalizations: [LocalizationInfo]) { + self.availableOfficialLocalizations = availableOfficialLocalizations + self.availableSavedLocalizations = availableSavedLocalizations + } + + public init(decoder: PostboxDecoder) { + self.availableOfficialLocalizations = decoder.decodeObjectArrayWithDecoderForKey("availableOfficialLocalizations") + self.availableSavedLocalizations = decoder.decodeObjectArrayWithDecoderForKey("availableSavedLocalizations") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.availableOfficialLocalizations, forKey: "availableOfficialLocalizations") + encoder.encodeObjectArray(self.availableSavedLocalizations, forKey: "availableSavedLocalizations") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? LocalizationListState else { + return false + } + + return self == to + } +} + +public func removeSavedLocalization(transaction: Transaction, languageCode: String) { + updateLocalizationListStateInteractively(transaction: transaction, { state in + var state = state + state.availableSavedLocalizations = state.availableSavedLocalizations.filter({ $0.languageCode != languageCode }) + return state + }) +} + +func updateLocalizationListStateInteractively(postbox: Postbox, _ f: @escaping (LocalizationListState) -> LocalizationListState) -> Signal { + return postbox.transaction { transaction -> Void in + updateLocalizationListStateInteractively(transaction: transaction, f) + } +} + +func updateLocalizationListStateInteractively(transaction: Transaction, _ f: @escaping (LocalizationListState) -> LocalizationListState) { + transaction.updatePreferencesEntry(key: PreferencesKeys.localizationListState, { current in + let previous = (current as? LocalizationListState) ?? LocalizationListState.defaultSettings + var updated = f(previous) + var removeOfficialIndices: [Int] = [] + var officialSet = Set() + for i in 0 ..< updated.availableOfficialLocalizations.count { + if officialSet.contains(updated.availableOfficialLocalizations[i].languageCode) { + removeOfficialIndices.append(i) + } else { + officialSet.insert(updated.availableOfficialLocalizations[i].languageCode) + } + } + for i in removeOfficialIndices.reversed() { + updated.availableOfficialLocalizations.remove(at: i) + } + var removeSavedIndices: [Int] = [] + var savedSet = Set() + for i in 0 ..< updated.availableSavedLocalizations.count { + if savedSet.contains(updated.availableSavedLocalizations[i].languageCode) { + removeSavedIndices.append(i) + } else { + savedSet.insert(updated.availableSavedLocalizations[i].languageCode) + } + } + for i in removeSavedIndices.reversed() { + updated.availableSavedLocalizations.remove(at: i) + } + return updated + }) +} + +public func synchronizedLocalizationListState(postbox: Postbox, network: Network) -> Signal { + return network.request(Api.functions.langpack.getLanguages(langPack: "")) + |> retryRequest + |> mapToSignal { languages -> Signal in + let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) + return postbox.transaction { transaction -> Void in + updateLocalizationListStateInteractively(transaction: transaction, { current in + var current = current + current.availableOfficialLocalizations = infos + return current + }) + } + |> ignoreValues + } +} diff --git a/submodules/TelegramCore/TelegramCore/LocalizationPreview.swift b/submodules/TelegramCore/TelegramCore/LocalizationPreview.swift new file mode 100644 index 0000000000..0c72cf5096 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LocalizationPreview.swift @@ -0,0 +1,27 @@ +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum RequestLocalizationPreviewError { + case generic +} + +public func requestLocalizationPreview(network: Network, identifier: String) -> Signal { + return network.request(Api.functions.langpack.getLanguage(langPack: "", langCode: identifier)) + |> mapError { _ -> RequestLocalizationPreviewError in + return .generic + } + |> map { language -> LocalizationInfo in + return LocalizationInfo(apiLanguage: language) + } +} diff --git a/submodules/TelegramCore/TelegramCore/LocalizationSettings.swift b/submodules/TelegramCore/TelegramCore/LocalizationSettings.swift new file mode 100644 index 0000000000..4328477ffd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LocalizationSettings.swift @@ -0,0 +1,95 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class LocalizationComponent: Equatable, PostboxCoding { + public let languageCode: String + public let localizedName: String + public let localization: Localization + public let customPluralizationCode: String? + + public init(languageCode: String, localizedName: String, localization: Localization, customPluralizationCode: String?) { + self.languageCode = languageCode + self.localizedName = localizedName + self.localization = localization + self.customPluralizationCode = customPluralizationCode + } + + public init(decoder: PostboxDecoder) { + self.languageCode = decoder.decodeStringForKey("lc", orElse: "") + self.localizedName = decoder.decodeStringForKey("localizedName", orElse: "") + self.localization = decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization + self.customPluralizationCode = decoder.decodeOptionalStringForKey("cpl") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeString(self.localizedName, forKey: "localizedName") + encoder.encodeObject(self.localization, forKey: "loc") + if let customPluralizationCode = self.customPluralizationCode { + encoder.encodeString(customPluralizationCode, forKey: "cpl") + } else { + encoder.encodeNil(forKey: "cpl") + } + } + + public static func ==(lhs: LocalizationComponent, rhs: LocalizationComponent) -> Bool { + if lhs.languageCode != rhs.languageCode { + return false + } + if lhs.localizedName != rhs.localizedName { + return false + } + if lhs.localization != rhs.localization { + return false + } + if lhs.customPluralizationCode != rhs.customPluralizationCode { + return false + } + return true + } +} + +public final class LocalizationSettings: PreferencesEntry, Equatable { + public let primaryComponent: LocalizationComponent + public let secondaryComponent: LocalizationComponent? + + public init(primaryComponent: LocalizationComponent, secondaryComponent: LocalizationComponent?) { + self.primaryComponent = primaryComponent + self.secondaryComponent = secondaryComponent + } + + public init(decoder: PostboxDecoder) { + if let languageCode = decoder.decodeOptionalStringForKey("lc") { + self.primaryComponent = LocalizationComponent(languageCode: languageCode, localizedName: "", localization: decoder.decodeObjectForKey("loc", decoder: { Localization(decoder: $0) }) as! Localization, customPluralizationCode: nil) + self.secondaryComponent = nil + } else { + self.primaryComponent = decoder.decodeObjectForKey("primaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as! LocalizationComponent + self.secondaryComponent = decoder.decodeObjectForKey("secondaryComponent", decoder: { LocalizationComponent(decoder: $0) }) as? LocalizationComponent + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.primaryComponent, forKey: "primaryComponent") + if let secondaryComponent = self.secondaryComponent { + encoder.encodeObject(secondaryComponent, forKey: "secondaryComponent") + } else { + encoder.encodeNil(forKey: "secondaryComponent") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? LocalizationSettings { + return self == to + } else { + return false + } + } + + public static func ==(lhs: LocalizationSettings, rhs: LocalizationSettings) -> Bool { + return lhs.primaryComponent == rhs.primaryComponent && lhs.secondaryComponent == rhs.secondaryComponent + } +} diff --git a/submodules/TelegramCore/TelegramCore/Localizations.swift b/submodules/TelegramCore/TelegramCore/Localizations.swift new file mode 100644 index 0000000000..36565b81b1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Localizations.swift @@ -0,0 +1,182 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func currentlySuggestedLocalization(network: Network, extractKeys: [String]) -> Signal { + return network.request(Api.functions.help.getConfig()) + |> retryRequest + |> mapToSignal { result -> Signal in + switch result { + case let .config(config): + if let suggestedLangCode = config.suggestedLangCode { + return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map(Optional.init) + } else { + return .single(nil) + } + } + } +} + +public func suggestedLocalizationInfo(network: Network, languageCode: String, extractKeys: [String]) -> Signal { + return combineLatest(network.request(Api.functions.langpack.getLanguages(langPack: "")), network.request(Api.functions.langpack.getStrings(langPack: "", langCode: languageCode, keys: extractKeys))) + |> retryRequest + |> map { languages, strings -> SuggestedLocalizationInfo in + var entries: [LocalizationEntry] = [] + for string in strings { + switch string { + case let .langPackString(key, value): + entries.append(.string(key: key, value: value)) + case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): + entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) + case let .langPackStringDeleted(key): + entries.append(.string(key: key, value: "")) + } + } + let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) + return SuggestedLocalizationInfo(languageCode: languageCode, extractedEntries: entries, availableLocalizations: infos) + } +} + +final class CachedLocalizationInfos: PostboxCoding { + let list: [LocalizationInfo] + + init(list: [LocalizationInfo]) { + self.list = list + } + + init(decoder: PostboxDecoder) { + self.list = decoder.decodeObjectArrayWithDecoderForKey("l") + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.list, forKey: "l") + } +} + +public func availableLocalizations(postbox: Postbox, network: Network, allowCached: Bool) -> Signal<[LocalizationInfo], NoError> { + let cached: Signal<[LocalizationInfo], NoError> + if allowCached { + cached = postbox.transaction { transaction -> Signal<[LocalizationInfo], NoError> in + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0))) as? CachedLocalizationInfos { + return .single(entry.list) + } + return .complete() + } |> switchToLatest + } else { + cached = .complete() + } + let remote = network.request(Api.functions.langpack.getLanguages(langPack: "")) + |> retryRequest + |> mapToSignal { languages -> Signal<[LocalizationInfo], NoError> in + let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) + return postbox.transaction { transaction -> [LocalizationInfo] in + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: CachedLocalizationInfos(list: infos), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + return infos + } + } + + return cached |> then(remote) +} + +public enum DownloadLocalizationError { + case generic +} + +public func downloadLocalization(network: Network, languageCode: String) -> Signal { + return network.request(Api.functions.langpack.getLangPack(langPack: "", langCode: languageCode)) + |> mapError { _ -> DownloadLocalizationError in + return .generic + } + |> map { result -> Localization in + let version: Int32 + var entries: [LocalizationEntry] = [] + switch result { + case let .langPackDifference(_, _, versionValue, strings): + version = versionValue + for string in strings { + switch string { + case let .langPackString(key, value): + entries.append(.string(key: key, value: value)) + case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): + entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) + case let .langPackStringDeleted(key): + entries.append(.string(key: key, value: "")) + } + } + } + + return Localization(version: version, entries: entries) + } +} + +public enum DownloadAndApplyLocalizationError { + case generic +} + +public func downloadAndApplyLocalization(accountManager: AccountManager, postbox: Postbox, network: Network, languageCode: String) -> Signal { + return requestLocalizationPreview(network: network, identifier: languageCode) + |> mapError { _ -> DownloadAndApplyLocalizationError in + return .generic + } + |> mapToSignal { preview -> Signal in + var primaryAndSecondaryLocalizations: [Signal] = [] + primaryAndSecondaryLocalizations.append(downloadLocalization(network: network, languageCode: preview.languageCode)) + if let secondaryCode = preview.baseLanguageCode { + primaryAndSecondaryLocalizations.append(downloadLocalization(network: network, languageCode: secondaryCode)) + } + return combineLatest(primaryAndSecondaryLocalizations) + |> mapError { _ -> DownloadAndApplyLocalizationError in + return .generic + } + |> mapToSignal { components -> Signal in + guard let primaryLocalization = components.first else { + return .fail(.generic) + } + var secondaryComponent: LocalizationComponent? + if let secondaryCode = preview.baseLanguageCode, components.count > 1 { + secondaryComponent = LocalizationComponent(languageCode: secondaryCode, localizedName: "", localization: components[1], customPluralizationCode: nil) + } + return accountManager.transaction { transaction -> Signal in + transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in + return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: preview.languageCode, localizedName: preview.localizedTitle, localization: primaryLocalization, customPluralizationCode: preview.customPluralizationCode), secondaryComponent: secondaryComponent) + }) + + return postbox.transaction { transaction -> Signal in + updateLocalizationListStateInteractively(transaction: transaction, { state in + var state = state + for i in 0 ..< state.availableSavedLocalizations.count { + if state.availableSavedLocalizations[i].languageCode == preview.languageCode { + state.availableSavedLocalizations.remove(at: i) + break + } + } + state.availableSavedLocalizations.insert(preview, at: 0) + return state + }) + + network.context.updateApiEnvironment { current in + return current?.withUpdatedLangPackCode(preview.languageCode) + } + + return network.request(Api.functions.help.test()) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + |> introduceError(DownloadAndApplyLocalizationError.self) + } + |> introduceError(DownloadAndApplyLocalizationError.self) + |> switchToLatest + } + |> introduceError(DownloadAndApplyLocalizationError.self) + |> switchToLatest + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Log.swift b/submodules/TelegramCore/TelegramCore/Log.swift new file mode 100644 index 0000000000..d84b6c2291 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Log.swift @@ -0,0 +1,453 @@ +import Foundation +import TelegramCorePrivateModule +#if os(macOS) + import SwiftSignalKitMac + import PostboxMac +#else + import SwiftSignalKit + import Postbox +#endif + +private let queue = DispatchQueue(label: "org.telegram.Telegram.trace", qos: .utility) + +public func trace2(_ what: @autoclosure() -> String) { + let string = what() + var rawTime = time_t() + time(&rawTime) + var timeinfo = tm() + localtime_r(&rawTime, &timeinfo) + + var curTime = timeval() + gettimeofday(&curTime, nil) + let milliseconds = curTime.tv_usec / 1000 + + //queue.async { + let result = String(format: "%d-%d-%d %02d:%02d:%03d %@", arguments: [Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(milliseconds), string]) + print(result) + //} +} + +public func trace1(_ domain: String, what: @autoclosure() -> String) { + let string = what() + var rawTime = time_t() + time(&rawTime) + var timeinfo = tm() + localtime_r(&rawTime, &timeinfo) + + var curTime = timeval() + gettimeofday(&curTime, nil) + let seconds = curTime.tv_sec + let milliseconds = curTime.tv_usec / 1000 + + queue.async { + let result = String(format: "[%@] %d-%d-%d %02d:%02d:%02d.%03d %@", arguments: [domain, Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(seconds), Int(milliseconds), string]) + + print(result) + } +} + +public func registerLoggingFunctions() { + setBridgingTraceFunction({ domain, what in + if let what = what { + if let domain = domain { + Logger.shared.log(domain, what as String) + } else { + Logger.shared.log("", what as String) + } + } + }) + setBridgingShortTraceFunction({ domain, what in + if let what = what { + if let domain = domain { + Logger.shared.shortLog(domain, what as String) + } else { + Logger.shared.shortLog("", what as String) + } + } + }) +} + +private var sharedLogger: Logger? + +private let binaryEventMarker: UInt64 = 0xcadebabef00dcafe + +public final class Logger { + private let queue = Queue(name: "org.telegram.Telegram.log", qos: .utility) + private let maxLength: Int = 2 * 1024 * 1024 + private let maxShortLength: Int = 1 * 1024 * 1024 + private let maxFiles: Int = 20 + + private let basePath: String + private var file: (ManagedFile, Int)? + private var shortFile: (ManagedFile, Int)? + + public var logToFile: Bool = true { + didSet { + let oldEnabled = self.logToConsole || oldValue + let newEnabled = self.logToConsole || self.logToFile + if oldEnabled != newEnabled { + NetworkSetLoggingEnabled(newEnabled) + } + } + } + public var logToConsole: Bool = true { + didSet { + let oldEnabled = self.logToFile || oldValue + let newEnabled = self.logToFile || self.logToConsole + if oldEnabled != newEnabled { + NetworkSetLoggingEnabled(newEnabled) + } + } + } + public var redactSensitiveData: Bool = true + + public static func setSharedLogger(_ logger: Logger) { + sharedLogger = logger + setPostboxLogger({ s in + Logger.shared.log("Postbox", s) + Logger.shared.shortLog("Postbox", s) + }) + } + + public static var shared: Logger { + if let sharedLogger = sharedLogger { + return sharedLogger + } else { + assertionFailure() + let tempLogger = Logger(basePath: "") + tempLogger.logToFile = false + tempLogger.logToConsole = false + return tempLogger + } + } + + public init(basePath: String) { + self.basePath = basePath + } + + public func collectLogs() -> Signal<[(String, String)], NoError> { + return Signal { subscriber in + self.queue.async { + var result: [(Date, String, String)] = [] + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) { + for url in files { + if url.lastPathComponent.hasPrefix("log-") { + if let creationDate = (try? url.resourceValues(forKeys: Set([.creationDateKey])))?.creationDate { + result.append((creationDate, url.lastPathComponent, url.path)) + } + } + } + } + result.sort(by: { $0.0 < $1.0 }) + subscriber.putNext(result.map { ($0.1, $0.2) }) + subscriber.putCompletion() + } + + return EmptyDisposable + } + } + + public func collectShortLogFiles() -> Signal<[(String, String)], NoError> { + return Signal { subscriber in + self.queue.async { + var result: [(Date, String, String)] = [] + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) { + for url in files { + if url.lastPathComponent.hasPrefix("critlog-") { + if let creationDate = (try? url.resourceValues(forKeys: Set([.creationDateKey])))?.creationDate { + result.append((creationDate, url.lastPathComponent, url.path)) + } + } + } + } + result.sort(by: { $0.0 < $1.0 }) + subscriber.putNext(result.map { ($0.1, $0.2) }) + subscriber.putCompletion() + } + + return EmptyDisposable + } + } + + public func collectShortLog() -> Signal<[(Double, String)], NoError> { + return Signal { subscriber in + self.queue.async { + var result: [(Date, String, String)] = [] + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) { + for url in files { + if url.lastPathComponent.hasPrefix("critlog-") { + if let creationDate = (try? url.resourceValues(forKeys: Set([.creationDateKey])))?.creationDate { + result.append((creationDate, url.lastPathComponent, url.path)) + } + } + } + } + result.sort(by: { $0.0 < $1.0 }) + + var events: [(Double, String)] = [] + for (_, _, filePath) in result.reversed() { + var fileEvents: [(Double, String)] = [] + if let data = try? Data(contentsOf: URL(fileURLWithPath: filePath), options: .mappedRead) { + let dataLength = data.count + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + var offset = 0 + while offset < dataLength { + let remainingLength = dataLength - offset + if remainingLength < 8 + 4 + 8 { + break + } + var maybeMarker: UInt64 = 0 + memcpy(&maybeMarker, bytes.advanced(by: offset), 8) + if maybeMarker == binaryEventMarker { + var length: Int32 = 0 + memcpy(&length, bytes.advanced(by: offset + 8), 4) + if length < 0 || length > dataLength - offset { + offset += 1 + } else { + var timestamp: Double = 0.0 + memcpy(×tamp, bytes.advanced(by: offset + 8 + 4), 8) + let eventStringData = Data(bytes: bytes.advanced(by: offset + 8 + 4 + 8), count: Int(length - 8)) + if let string = String(data: eventStringData, encoding: .utf8) { + fileEvents.append((timestamp, string)) + } + offset += 8 + 4 + Int(length) + } + } else { + offset += 1 + } + } + } + + events.append(contentsOf: fileEvents.reversed()) + if events.count > 1000 { + break + } + } + } + if events.count > 1000 { + events.removeLast(events.count - 1000) + } + subscriber.putNext(events) + subscriber.putCompletion() + } + + return EmptyDisposable + } + } + + public func log(_ tag: String, _ what: @autoclosure () -> String) { + if !self.logToFile && !self.logToConsole { + return + } + + let string = what() + + var rawTime = time_t() + time(&rawTime) + var timeinfo = tm() + localtime_r(&rawTime, &timeinfo) + + var curTime = timeval() + gettimeofday(&curTime, nil) + let milliseconds = curTime.tv_usec / 1000 + + var consoleContent: String? + if self.logToConsole { + let content = String(format: "[%@] %d-%d-%d %02d:%02d:%02d.%03d %@", arguments: [tag, Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(timeinfo.tm_sec), Int(milliseconds), string]) + consoleContent = content + print(content) + } + + if self.logToFile { + self.queue.async { + let content: String + if let consoleContent = consoleContent { + content = consoleContent + } else { + content = String(format: "[%@] %d-%d-%d %02d:%02d:%02d.%03d %@", arguments: [tag, Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(timeinfo.tm_sec), Int(milliseconds), string]) + } + + var currentFile: ManagedFile? + var openNew = false + if let (file, length) = self.file { + if length >= self.maxLength { + self.file = nil + openNew = true + } else { + currentFile = file + } + } else { + openNew = true + } + if openNew { + let _ = try? FileManager.default.createDirectory(atPath: self.basePath, withIntermediateDirectories: true, attributes: nil) + + var createNew = false + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) { + var minCreationDate: (Date, URL)? + var maxCreationDate: (Date, URL)? + var count = 0 + for url in files { + if url.lastPathComponent.hasPrefix("log-") { + if let values = try? url.resourceValues(forKeys: Set([URLResourceKey.creationDateKey])), let creationDate = values.creationDate { + count += 1 + if minCreationDate == nil || minCreationDate!.0 > creationDate { + minCreationDate = (creationDate, url) + } + if maxCreationDate == nil || maxCreationDate!.0 < creationDate { + maxCreationDate = (creationDate, url) + } + } + } + } + if let (_, url) = minCreationDate, count >= self.maxFiles { + let _ = try? FileManager.default.removeItem(at: url) + } + if let (_, url) = maxCreationDate { + var value = stat() + if stat(url.path, &value) == 0 && Int(value.st_size) < self.maxLength { + if let file = ManagedFile(queue: self.queue, path: url.path, mode: .append) { + self.file = (file, Int(value.st_size)) + currentFile = file + } + } else { + createNew = true + } + } else { + createNew = true + } + } + + if createNew { + let fileName = String(format: "log-%d-%d-%d_%02d-%02d-%02d.%03d.txt", arguments: [Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(timeinfo.tm_sec), Int(milliseconds)]) + + let path = self.basePath + "/" + fileName + + if let file = ManagedFile(queue: self.queue, path: path, mode: .append) { + self.file = (file, 0) + currentFile = file + } + } + } + + if let currentFile = currentFile { + if let data = content.data(using: .utf8) { + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + let _ = currentFile.write(bytes, count: data.count) + } + var newline: UInt8 = 0x0a + let _ = currentFile.write(&newline, count: 1) + if let file = self.file { + self.file = (file.0, file.1 + data.count + 1) + } else { + assertionFailure() + } + } + } + } + } + } + + public func shortLog(_ tag: String, _ what: @autoclosure () -> String) { + let string = what() + + var rawTime = time_t() + time(&rawTime) + var timeinfo = tm() + localtime_r(&rawTime, &timeinfo) + + var curTime = timeval() + gettimeofday(&curTime, nil) + let milliseconds = curTime.tv_usec / 1000 + + let timestamp: Double = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970 + + self.queue.async { + let content = WriteBuffer() + var binaryEventMarkerValue: UInt64 = binaryEventMarker + content.write(&binaryEventMarkerValue, offset: 0, length: 8) + let stringData = string.data(using: .utf8) ?? Data() + var lengthValue: Int32 = 8 + Int32(stringData.count) + content.write(&lengthValue, offset: 0, length: 4) + var timestampValue: Double = timestamp + content.write(×tampValue, offset: 0, length: 8) + content.write(stringData) + let contentData = content.makeData() + + var currentFile: ManagedFile? + var openNew = false + if let (file, length) = self.shortFile { + if length >= self.maxShortLength { + self.shortFile = nil + openNew = true + } else { + currentFile = file + } + } else { + openNew = true + } + if openNew { + let _ = try? FileManager.default.createDirectory(atPath: self.basePath, withIntermediateDirectories: true, attributes: nil) + + var createNew = false + if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) { + var minCreationDate: (Date, URL)? + var maxCreationDate: (Date, URL)? + var count = 0 + for url in files { + if url.lastPathComponent.hasPrefix("critlog-") { + if let values = try? url.resourceValues(forKeys: Set([URLResourceKey.creationDateKey])), let creationDate = values.creationDate { + count += 1 + if minCreationDate == nil || minCreationDate!.0 > creationDate { + minCreationDate = (creationDate, url) + } + if maxCreationDate == nil || maxCreationDate!.0 < creationDate { + maxCreationDate = (creationDate, url) + } + } + } + } + if let (_, url) = minCreationDate, count >= self.maxFiles { + let _ = try? FileManager.default.removeItem(at: url) + } + if let (_, url) = maxCreationDate { + var value = stat() + if stat(url.path, &value) == 0 && Int(value.st_size) < self.maxShortLength { + if let file = ManagedFile(queue: self.queue, path: url.path, mode: .append) { + self.shortFile = (file, Int(value.st_size)) + currentFile = file + } + } else { + createNew = true + } + } else { + createNew = true + } + } + + if createNew { + let fileName = String(format: "critlog-%d-%d-%d_%02d-%02d-%02d.%03d.txt", arguments: [Int(timeinfo.tm_year) + 1900, Int(timeinfo.tm_mon + 1), Int(timeinfo.tm_mday), Int(timeinfo.tm_hour), Int(timeinfo.tm_min), Int(timeinfo.tm_sec), Int(milliseconds)]) + + let path = self.basePath + "/" + fileName + + if let file = ManagedFile(queue: self.queue, path: path, mode: .append) { + self.shortFile = (file, 0) + currentFile = file + } + } + } + + if let currentFile = currentFile { + let contentDataCount = contentData.count + contentData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + let _ = currentFile.write(bytes, count: contentDataCount) + } + if let shortFile = self.shortFile { + self.shortFile = (shortFile.0, shortFile.1 + contentDataCount) + } else { + assertionFailure() + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/LoggedOutAccountAttribute.swift b/submodules/TelegramCore/TelegramCore/LoggedOutAccountAttribute.swift new file mode 100644 index 0000000000..c7e0283d51 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoggedOutAccountAttribute.swift @@ -0,0 +1,21 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class LoggedOutAccountAttribute: AccountRecordAttribute { + public init() { + } + + public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } + + public func isEqual(to: AccountRecordAttribute) -> Bool { + return to is LoggedOutAccountAttribute + } +} diff --git a/submodules/TelegramCore/TelegramCore/LoggingSettings.swift b/submodules/TelegramCore/TelegramCore/LoggingSettings.swift new file mode 100644 index 0000000000..8e283e9848 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/LoggingSettings.swift @@ -0,0 +1,98 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public final class LoggingSettings: PreferencesEntry, Equatable { + public let logToFile: Bool + public let logToConsole: Bool + public let redactSensitiveData: Bool + + #if DEBUG + public static var defaultSettings = LoggingSettings(logToFile: true, logToConsole: true, redactSensitiveData: true) + #else + public static var defaultSettings = LoggingSettings(logToFile: false, logToConsole: false, redactSensitiveData: true) + #endif + + public init(logToFile: Bool, logToConsole: Bool, redactSensitiveData: Bool) { + self.logToFile = logToFile + self.logToConsole = logToConsole + self.redactSensitiveData = redactSensitiveData + } + + public init(decoder: PostboxDecoder) { + self.logToFile = decoder.decodeInt32ForKey("logToFile", orElse: 0) != 0 + self.logToConsole = decoder.decodeInt32ForKey("logToConsole", orElse: 0) != 0 + self.redactSensitiveData = decoder.decodeInt32ForKey("redactSensitiveData", orElse: 1) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.logToFile ? 1 : 0, forKey: "logToFile") + encoder.encodeInt32(self.logToConsole ? 1 : 0, forKey: "logToConsole") + encoder.encodeInt32(self.redactSensitiveData ? 1 : 0, forKey: "redactSensitiveData") + } + + public func withUpdatedLogToFile(_ logToFile: Bool) -> LoggingSettings { + return LoggingSettings(logToFile: logToFile, logToConsole: self.logToConsole, redactSensitiveData: self.redactSensitiveData) + } + + public func withUpdatedLogToConsole(_ logToConsole: Bool) -> LoggingSettings { + return LoggingSettings(logToFile: self.logToFile, logToConsole: logToConsole, redactSensitiveData: self.redactSensitiveData) + } + + public func withUpdatedRedactSensitiveData(_ redactSensitiveData: Bool) -> LoggingSettings { + return LoggingSettings(logToFile: self.logToFile, logToConsole: self.logToConsole, redactSensitiveData: redactSensitiveData) + } + + public static func ==(lhs: LoggingSettings, rhs: LoggingSettings) -> Bool { + if lhs.logToFile != rhs.logToFile { + return false + } + if lhs.logToConsole != rhs.logToConsole { + return false + } + if lhs.redactSensitiveData != rhs.redactSensitiveData { + return false + } + return true + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? LoggingSettings else { + return false + } + + return self == to + } +} + +public func updateLoggingSettings(accountManager: AccountManager, _ f: @escaping (LoggingSettings) -> LoggingSettings) -> Signal { + return accountManager.transaction { transaction -> Void in + var updated: LoggingSettings? + transaction.updateSharedData(SharedDataKeys.loggingSettings, { current in + if let current = current as? LoggingSettings { + updated = f(current) + return updated + } else { + updated = f(LoggingSettings.defaultSettings) + return updated + } + }) + + if let updated = updated { + Logger.shared.logToFile = updated.logToFile + Logger.shared.logToConsole = updated.logToConsole + Logger.shared.redactSensitiveData = updated.redactSensitiveData + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/MD5.swift b/submodules/TelegramCore/TelegramCore/MD5.swift new file mode 100644 index 0000000000..2eca98165a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MD5.swift @@ -0,0 +1,13 @@ +import Foundation +import TelegramCorePrivateModule +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public extension MemoryBuffer { + public func md5Digest() -> Data { + return CryptoMD5(self.memory, Int32(self.length)) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManageChannelDiscussionGroup.swift b/submodules/TelegramCore/TelegramCore/ManageChannelDiscussionGroup.swift new file mode 100644 index 0000000000..41a3bf19c9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManageChannelDiscussionGroup.swift @@ -0,0 +1,105 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public enum AvailableChannelDiscussionGroupError { + case generic +} + +public func availableGroupsForChannelDiscussion(postbox: Postbox, network: Network) -> Signal<[Peer], AvailableChannelDiscussionGroupError> { + return network.request(Api.functions.channels.getGroupsForDiscussion()) + |> mapError { error in + return .generic + } + |> mapToSignal { result -> Signal<[Peer], AvailableChannelDiscussionGroupError> in + let chats: [Api.Chat] + switch result { + case let .chats(c): + chats = c + case let .chatsSlice(_, c): + chats = c + } + + let peers = chats.compactMap(parseTelegramGroupOrChannel) + return postbox.transaction { transation -> [Peer] in + updatePeers(transaction: transation, peers: peers, update: { _, updated in updated }) + return peers + } + |> introduceError(AvailableChannelDiscussionGroupError.self) + } +} + +public enum ChannelDiscussionGroupError { + case generic + case groupHistoryIsCurrentlyPrivate + case hasNotPermissions +} + +public func updateGroupDiscussionForChannel(network: Network, postbox: Postbox, channelId: PeerId, groupId: PeerId?) -> Signal { + + return postbox.transaction { transaction -> (channel: Peer?, group: Peer?) in + return (channel: transaction.getPeer(channelId), group: groupId != nil ? transaction.getPeer(groupId!) : nil) + } + |> mapError { _ in ChannelDiscussionGroupError.generic } + |> mapToSignal { peers -> Signal in + guard let channel = peers.channel else { + return .fail(.generic) + } + + let tempGroupApi = peers.group != nil ? apiInputChannel(peers.group!) : Api.InputChannel.inputChannelEmpty + + guard let apiChannel = apiInputChannel(channel), let apiGroup = tempGroupApi else { + return .fail(.generic) + } + + return network.request(Api.functions.channels.setDiscussionGroup(broadcast: apiChannel, group: apiGroup)) + |> map { result in + switch result { + case .boolTrue: + return true + case .boolFalse: + return false + } + } + |> `catch` { error -> Signal in + if error.errorDescription == "LINK_NOT_MODIFIED" { + return .single(true) + } else if error.errorDescription == "MEGAGROUP_PREHISTORY_HIDDEN" { + return .fail(.groupHistoryIsCurrentlyPrivate) + } else if error.errorDescription == "CHAT_ADMIN_REQUIRED" { + return .fail(.hasNotPermissions) + } + return .fail(.generic) + } + } + |> mapToSignal { result in + if result { + return postbox.transaction { transaction in + var previousGroupId: PeerId? + transaction.updatePeerCachedData(peerIds: Set([channelId]), update: { (_, current) -> CachedPeerData? in + let current: CachedChannelData = current as? CachedChannelData ?? CachedChannelData() + previousGroupId = current.linkedDiscussionPeerId + return current.withUpdatedLinkedDiscussionPeerId(groupId) + }) + if let associatedId = previousGroupId ?? groupId { + transaction.updatePeerCachedData(peerIds: Set([associatedId]), update: { (_, current) -> CachedPeerData? in + let cachedData = (current as? CachedChannelData ?? CachedChannelData()) + return cachedData.withUpdatedLinkedDiscussionPeerId(groupId == nil ? nil : channelId) + }) + } + } + |> introduceError(ChannelDiscussionGroupError.self) + |> map { _ in + return result + } + } else { + return .single(result) + } + } + +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedAccountPresence.swift b/submodules/TelegramCore/TelegramCore/ManagedAccountPresence.swift new file mode 100644 index 0000000000..9e11f5d70f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedAccountPresence.swift @@ -0,0 +1,102 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +#if os(macOS) +private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else +private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private final class AccountPresenceManagerImpl { + private let queue: Queue + private let network: Network + let isPerformingUpdate = ValuePromise(false, ignoreRepeated: true) + + private var shouldKeepOnlinePresenceDisposable: Disposable? + private let currentRequestDisposable = MetaDisposable() + private var onlineTimer: SignalKitTimer? + + init(queue: Queue, shouldKeepOnlinePresence: Signal, network: Network) { + self.queue = queue + self.network = network + + self.shouldKeepOnlinePresenceDisposable = (shouldKeepOnlinePresence + |> distinctUntilChanged + |> deliverOn(self.queue)).start(next: { [weak self] value in + self?.updatePresence(value) + }) + } + + deinit { + assert(self.queue.isCurrent()) + self.shouldKeepOnlinePresenceDisposable?.dispose() + self.currentRequestDisposable.dispose() + self.onlineTimer?.invalidate() + } + + private func updatePresence(_ isOnline: Bool) { + let request: Signal + if isOnline { + let timer = SignalKitTimer(timeout: 30.0, repeat: false, completion: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.updatePresence(true) + }, queue: self.queue) + self.onlineTimer = timer + timer.start() + request = self.network.request(Api.functions.account.updateStatus(offline: .boolFalse)) + } else { + self.onlineTimer?.invalidate() + self.onlineTimer = nil + request = self.network.request(Api.functions.account.updateStatus(offline: .boolTrue)) + } + self.isPerformingUpdate.set(true) + self.currentRequestDisposable.set((request + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> deliverOn(self.queue)).start(completed: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.isPerformingUpdate.set(false) + })) + } +} + +final class AccountPresenceManager { + private let queue = Queue() + private let impl: QueueLocalObject + + init(shouldKeepOnlinePresence: Signal, network: Network) { + let queue = self.queue + self.impl = QueueLocalObject(queue: self.queue, generate: { + return AccountPresenceManagerImpl(queue: queue, shouldKeepOnlinePresence: shouldKeepOnlinePresence, network: network) + }) + } + + func isPerformingUpdate() -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.isPerformingUpdate.get().start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedAppConfigurationUpdates.swift b/submodules/TelegramCore/TelegramCore/ManagedAppConfigurationUpdates.swift new file mode 100644 index 0000000000..7f99224b2a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedAppConfigurationUpdates.swift @@ -0,0 +1,33 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedAppConfigurationUpdates(postbox: Postbox, network: Network) -> Signal { + let poll = Signal { subscriber in + return (network.request(Api.functions.help.getAppConfig()) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + if let data = JSON(apiJson: result) { + updateAppConfiguration(transaction: transaction, { configuration -> AppConfiguration in + var configuration = configuration + configuration.data = data + return configuration + }) + } + } + }).start() + } + return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedAutodownloadSettingsUpdates.swift b/submodules/TelegramCore/TelegramCore/ManagedAutodownloadSettingsUpdates.swift new file mode 100644 index 0000000000..ae0623707a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedAutodownloadSettingsUpdates.swift @@ -0,0 +1,52 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedAutodownloadSettingsUpdates(accountManager: AccountManager, network: Network) -> Signal { + let poll = Signal { subscriber in + return (network.request(Api.functions.account.getAutoDownloadSettings()) + |> retryRequest + |> mapToSignal { result -> Signal in + return updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in + return AutodownloadSettings(apiAutodownloadSettings: result) + }) + }).start() + } + return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} + +public enum SavedAutodownloadPreset { + case low + case medium + case high +} + +public func saveAutodownloadSettings(account: Account, preset: SavedAutodownloadPreset, settings: AutodownloadPresetSettings) -> Signal { + var flags: Int32 = 0 + switch preset { + case .low: + flags |= (1 << 0) + case .high: + flags |= (1 << 1) + default: + break + } + return account.network.request(Api.functions.account.saveAutoDownloadSettings(flags: flags, settings: apiAutodownloadPresetSettings(settings))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedAutoremoveMessageOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedAutoremoveMessageOperations.swift new file mode 100644 index 0000000000..4a4c1c7f4e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedAutoremoveMessageOperations.swift @@ -0,0 +1,108 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +#if os(macOS) + private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else + private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private final class ManagedAutoremoveMessageOperationsHelper { + var entry: (TimestampBasedMessageAttributesEntry, MetaDisposable)? + + func update(_ head: TimestampBasedMessageAttributesEntry?) -> (disposeOperations: [Disposable], beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)] = [] + + if self.entry?.0.index != head?.index { + if let (_, disposable) = self.entry { + self.entry = nil + disposeOperations.append(disposable) + } + if let head = head { + let disposable = MetaDisposable() + self.entry = (head, disposable) + beginOperations.append((head, disposable)) + } + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + if let entry = entry { + return [entry.1] + } else { + return [] + } + } +} + +func managedAutoremoveMessageOperations(postbox: Postbox) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedAutoremoveMessageOperationsHelper()) + + let disposable = postbox.timestampBasedMessageAttributesView(tag: 0).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)]) in + return helper.update(view.head) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + let signal = Signal.complete() + |> suspendAwareDelay(max(0.0, Double(entry.timestamp) - timestamp), queue: Queue.concurrentDefaultQueue()) + |> then(postbox.transaction { transaction -> Void in + if let message = transaction.getMessage(entry.messageId) { + if message.id.peerId.namespace == Namespaces.Peer.SecretChat { + deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [entry.messageId]) + } else { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var updatedMedia = currentMessage.media + for i in 0 ..< updatedMedia.count { + if let _ = updatedMedia[i] as? TelegramMediaImage { + updatedMedia[i] = TelegramMediaExpiredContent(data: .image) + } else if let _ = updatedMedia[i] as? TelegramMediaFile { + updatedMedia[i] = TelegramMediaExpiredContent(data: .file) + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia)) + }) + } + } + transaction.removeTimestampBasedMessageAttribute(tag: 0, messageId: entry.messageId) + }) + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + disposable.dispose() + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedChatListHoles.swift b/submodules/TelegramCore/TelegramCore/ManagedChatListHoles.swift new file mode 100644 index 0000000000..cf2462f09e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedChatListHoles.swift @@ -0,0 +1,69 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private final class ManagedChatListHolesState { + private var holeDisposables: [ChatListHolesEntry: Disposable] = [:] + + func clearDisposables() -> [Disposable] { + let disposables = Array(self.holeDisposables.values) + self.holeDisposables.removeAll() + return disposables + } + + func update(entries: Set) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) { + var removed: [Disposable] = [] + var added: [ChatListHolesEntry: MetaDisposable] = [:] + + for (entry, disposable) in self.holeDisposables { + if !entries.contains(entry) { + removed.append(disposable) + self.holeDisposables.removeValue(forKey: entry) + } + } + + for entry in entries { + if self.holeDisposables[entry] == nil { + let disposable = MetaDisposable() + self.holeDisposables[entry] = disposable + added[entry] = disposable + } + } + + return (removed, added) + } +} + +func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: PeerId) -> Signal { + return Signal { _ in + let state = Atomic(value: ManagedChatListHolesState()) + + let disposable = postbox.chatListHolesView().start(next: { view in + let (removed, added) = state.with { state -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) in + return state.update(entries: view.entries) + } + + for disposable in removed { + disposable.dispose() + } + + for (entry, disposable) in added { + disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: entry.groupId, hole: entry.hole).start()) + } + }) + + return ActionDisposable { + disposable.dispose() + for disposable in state.with({ state -> [Disposable] in + state.clearDisposables() + }) { + disposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift new file mode 100644 index 0000000000..8475bf1439 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift @@ -0,0 +1,360 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedCloudChatRemoveMessagesOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, (entry.contents is CloudChatRemoveMessagesOperation || entry.contents is CloudChatRemoveChatOperation || entry.contents is CloudChatClearHistoryOperation) { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedCloudChatRemoveMessagesOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedCloudChatRemoveMessagesOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.CloudChatRemoveMessages, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? CloudChatRemoveMessagesOperation { + if let peer = transaction.getPeer(entry.peerId) { + return removeMessages(postbox: postbox, network: network, stateManager: stateManager, peer: peer, operation: operation) + } else { + return .complete() + } + } else if let operation = entry.contents as? CloudChatRemoveChatOperation { + if let peer = transaction.getPeer(entry.peerId) { + return removeChat(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, peer: peer, operation: operation) + } else { + return .complete() + } + } else if let operation = entry.contents as? CloudChatClearHistoryOperation { + if let peer = transaction.getPeer(entry.peerId) { + return clearHistory(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, peer: peer, operation: operation) + } else { + return .complete() + } + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func removeMessages(postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatRemoveMessagesOperation) -> Signal { + if peer.id.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + var signal: Signal = .complete() + for s in stride(from: 0, to: operation.messageIds.count, by: 100) { + let ids = Array(operation.messageIds[s ..< min(s + 100, operation.messageIds.count)]) + let partSignal = network.request(Api.functions.channels.deleteMessages(channel: inputChannel, id: ids.map { $0.id })) + |> map { result -> Api.messages.AffectedMessages? in + return result + } + |> `catch` { _ in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updateChannelPts(channelId: peer.id.id, pts: pts, ptsCount: ptsCount)]) + } + } + return .complete() + } + signal = signal + |> then(partSignal) + } + return signal + } else { + return .complete() + } + } else { + var flags: Int32 + switch operation.type { + case .forEveryone: + flags = (1 << 0) + default: + flags = 0 + } + + var signal: Signal = .complete() + for s in stride(from: 0, to: operation.messageIds.count, by: 100) { + let ids = Array(operation.messageIds[s ..< min(s + 100, operation.messageIds.count)]) + let partSignal = network.request(Api.functions.messages.deleteMessages(flags: flags, id: ids.map { $0.id })) + |> map { result -> Api.messages.AffectedMessages? in + return result + } + |> `catch` { _ in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } + return .complete() + } + + signal = signal + |> then(partSignal) + } + return signal + } +} + +private func removeChat(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatRemoveChatOperation) -> Signal { + if peer.id.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + let signal: Signal + if operation.deleteGloballyIfPossible { + signal = network.request(Api.functions.channels.deleteChannel(channel: inputChannel)) + |> `catch` { _ -> Signal in + return network.request(Api.functions.channels.leaveChannel(channel: inputChannel)) + } + } else { + signal = network.request(Api.functions.channels.leaveChannel(channel: inputChannel)) + } + + let reportSignal: Signal + if let inputPeer = apiInputPeer(peer), operation.reportChatSpam { + reportSignal = network.request(Api.functions.messages.reportSpam(peer: inputPeer)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + } else { + reportSignal = .single(.boolTrue) + } + + return combineLatest(signal + |> map { result -> Api.Updates? in + return result + } + |> `catch` { _ in + return .single(nil) + }, reportSignal) + |> mapToSignal { updates, _ in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } + } else { + return .complete() + } + } else if peer.id.namespace == Namespaces.Peer.CloudGroup { + let deleteUser: Signal = network.request(Api.functions.messages.deleteChatUser(chatId: peer.id.id, userId: Api.InputUser.inputUserSelf)) + |> map { result -> Api.Updates? in + return result + } + |> `catch` { _ in + return .single(nil) + } + |> mapToSignal { updates in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } + let reportSignal: Signal + if let inputPeer = apiInputPeer(peer), operation.reportChatSpam { + reportSignal = network.request(Api.functions.messages.reportSpam(peer: inputPeer)) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + } else { + reportSignal = .complete() + } + let deleteMessages: Signal + if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) { + deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer) + } else { + deleteMessages = .complete() + } + return deleteMessages + |> then(deleteUser) + |> then(reportSignal) + |> then(postbox.transaction { transaction -> Void in + clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id) + }) + } else if peer.id.namespace == Namespaces.Peer.CloudUser { + if let inputPeer = apiInputPeer(peer) { + let reportSignal: Signal + if let inputPeer = apiInputPeer(peer), operation.reportChatSpam { + reportSignal = network.request(Api.functions.messages.reportSpam(peer: inputPeer)) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + } else { + reportSignal = .complete() + } + return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer) + |> then(reportSignal) + |> then(postbox.transaction { transaction -> Void in + clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id) + }) + } else { + return .complete() + } + } else { + return .complete() + } +} + +private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, type: InteractiveMessagesDeletionType) -> Signal { + var flags: Int32 = 0 + if justClear { + flags |= 1 << 0 + } + if case .forEveryone = type { + flags |= 1 << 1 + } + let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId)) + |> map { result -> Api.messages.AffectedHistory? in + return result + } + |> `catch` { _ -> Signal in + return .fail(true) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedHistory(pts, ptsCount, offset): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + if offset == 0 { + return .fail(true) + } else { + return .complete() + } + } + } else { + return .fail(true) + } + } + return (signal |> restart) + |> `catch` { _ -> Signal in + return .complete() + } +} + +private func clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal { + if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser { + if let inputPeer = apiInputPeer(peer) { + return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type) + } else { + return .complete() + } + } else if peer.id.namespace == Namespaces.Peer.CloudChannel, let inputChannel = apiInputChannel(peer) { + return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + assertionFailure() + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedConfigurationUpdates.swift b/submodules/TelegramCore/TelegramCore/ManagedConfigurationUpdates.swift new file mode 100644 index 0000000000..244d22fb1f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedConfigurationUpdates.swift @@ -0,0 +1,100 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedConfigurationUpdates(accountManager: AccountManager, postbox: Postbox, network: Network) -> Signal { + let poll = Signal { subscriber in + return (network.request(Api.functions.help.getConfig()) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Signal in + switch result { + case let .config(config): + var addressList: [Int: [MTDatacenterAddress]] = [:] + for option in config.dcOptions { + switch option { + case let .dcOption(flags, id, ipAddress, port, secret): + let preferForMedia = (flags & (1 << 1)) != 0 + if addressList[Int(id)] == nil { + addressList[Int(id)] = [] + } + let restrictToTcp = (flags & (1 << 2)) != 0 + let isCdn = (flags & (1 << 3)) != 0 + let preferForProxy = (flags & (1 << 4)) != 0 + addressList[Int(id)]!.append(MTDatacenterAddress(ip: ipAddress, port: UInt16(port), preferForMedia: preferForMedia, restrictToTcp: restrictToTcp, cdn: isCdn, preferForProxy: preferForProxy, secret: secret?.makeData())) + } + } + network.context.performBatchUpdates { + for (id, list) in addressList { + network.context.updateAddressSetForDatacenter(withId: id, addressSet: MTDatacenterAddressSet(addressList: list), forceUpdateSchemes: false) + } + } + + let blockedMode = (config.flags & 8) != 0 + updateNetworkSettingsInteractively(transaction: transaction, network: network, { settings in + var settings = settings + settings.reducedBackupDiscoveryTimeout = blockedMode + settings.applicationUpdateUrlPrefix = config.autoupdateUrlPrefix + return settings + }) + + updateRemoteStorageConfiguration(transaction: transaction, configuration: RemoteStorageConfiguration(webDocumentsHostDatacenterId: config.webfileDcId)) + + transaction.updatePreferencesEntry(key: PreferencesKeys.suggestedLocalization, { entry in + var currentLanguageCode: String? + if let entry = entry as? SuggestedLocalizationEntry { + currentLanguageCode = entry.languageCode + } + if currentLanguageCode != config.suggestedLangCode { + if let suggestedLangCode = config.suggestedLangCode { + return SuggestedLocalizationEntry(languageCode: suggestedLangCode, isSeen: false) + } else { + return nil + } + } + return entry + }) + + updateLimitsConfiguration(transaction: transaction, configuration: LimitsConfiguration(maxPinnedChatCount: config.pinnedDialogsCountMax, maxArchivedPinnedChatCount: config.pinnedInfolderCountMax, maxGroupMemberCount: config.chatSizeMax, maxSupergroupMemberCount: config.megagroupSizeMax, maxMessageForwardBatchSize: config.forwardedCountMax, maxSavedGifCount: config.savedGifsLimit, maxRecentStickerCount: config.stickersRecentLimit, maxMessageEditingInterval: config.editTimeLimit, maxMediaCaptionLength: config.captionLengthMax, canRemoveIncomingMessagesInPrivateChats: (config.flags & (1 << 6)) != 0, maxMessageRevokeInterval: config.revokeTimeLimit, maxMessageRevokeIntervalInPrivateChats: config.revokePmTimeLimit)) + + updateSearchBotsConfiguration(transaction: transaction, configuration: SearchBotsConfiguration(imageBotUsername: config.imgSearchUsername, gifBotUsername: config.gifSearchUsername, venueBotUsername: config.venueSearchUsername)) + + return accountManager.transaction { transaction -> Signal in + let (primary, secondary) = getLocalization(transaction) + var invalidateLocalization = false + if primary.version != config.langPackVersion { + invalidateLocalization = true + } + if let secondary = secondary, let baseLangPackVersion = config.baseLangPackVersion { + if secondary.version != baseLangPackVersion { + invalidateLocalization = true + } + } + if invalidateLocalization { + return postbox.transaction { transaction -> Void in + addSynchronizeLocalizationUpdatesOperation(transaction: transaction) + } + } else { + return .complete() + } + } + |> switchToLatest + } + } + |> switchToLatest + }).start() + } + + return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedConsumePersonalMessagesActions.swift b/submodules/TelegramCore/TelegramCore/ManagedConsumePersonalMessagesActions.swift new file mode 100644 index 0000000000..1b05b931ef --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedConsumePersonalMessagesActions.swift @@ -0,0 +1,270 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedConsumePersonalMessagesActionsHelper { + var operationDisposables: [MessageId: Disposable] = [:] + var validateDisposables: [InvalidatedMessageHistoryTagsSummaryEntry: Disposable] = [:] + + func update(entries: [PendingMessageActionsEntry], invalidateEntries: Set) -> (disposeOperations: [Disposable], beginOperations: [(PendingMessageActionsEntry, MetaDisposable)], beginValidateOperations: [(InvalidatedMessageHistoryTagsSummaryEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PendingMessageActionsEntry, MetaDisposable)] = [] + var beginValidateOperations: [(InvalidatedMessageHistoryTagsSummaryEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validIds = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.id.peerId) { + hasRunningOperationForPeerId.insert(entry.id.peerId) + validIds.insert(entry.id) + + if self.operationDisposables[entry.id] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.id] = disposable + } + } + } + + var removeMergedIds: [MessageId] = [] + for (id, disposable) in self.operationDisposables { + if !validIds.contains(id) { + removeMergedIds.append(id) + disposeOperations.append(disposable) + } + } + + for id in removeMergedIds { + self.operationDisposables.removeValue(forKey: id) + } + + var validInvalidateEntries = Set() + + for entry in invalidateEntries { + if !hasRunningOperationForPeerId.contains(entry.key.peerId) { + validInvalidateEntries.insert(entry) + if self.validateDisposables[entry] == nil { + let disposable = MetaDisposable() + beginValidateOperations.append((entry, disposable)) + self.validateDisposables[entry] = disposable + } + } + } + + var removeValidateEntries: [InvalidatedMessageHistoryTagsSummaryEntry] = [] + for (entry, disposable) in self.validateDisposables { + if !validInvalidateEntries.contains(entry) { + removeValidateEntries.append(entry) + disposeOperations.append(disposable) + } + } + + for entry in removeValidateEntries { + self.validateDisposables.removeValue(forKey: entry) + } + + return (disposeOperations, beginOperations, beginValidateOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenAction(postbox: Postbox, type: PendingMessageActionType, id: MessageId, _ f: @escaping (Transaction, PendingMessageActionsEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PendingMessageActionsEntry? + + if let action = transaction.getPendingMessageAction(type: type, id: id) as? ConsumePersonalMessageAction { + result = PendingMessageActionsEntry(id: id, action: action) + } + + return f(transaction, result) + } |> switchToLatest +} + +func managedConsumePersonalMessagesActions(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedConsumePersonalMessagesActionsHelper()) + + let actionsKey = PostboxViewKey.pendingMessageActions(type: .consumeUnseenPersonalMessage) + let invalidateKey = PostboxViewKey.invalidatedMessageHistoryTagSummaries(tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud) + let disposable = postbox.combinedView(keys: [actionsKey, invalidateKey]).start(next: { view in + var entries: [PendingMessageActionsEntry] = [] + var invalidateEntries = Set() + if let v = view.views[actionsKey] as? PendingMessageActionsView { + entries = v.entries + } + if let v = view.views[invalidateKey] as? InvalidatedMessageHistoryTagSummariesView { + invalidateEntries = v.entries + } + + let (disposeOperations, beginOperations, beginValidateOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PendingMessageActionsEntry, MetaDisposable)], beginValidateOperations: [(InvalidatedMessageHistoryTagsSummaryEntry, MetaDisposable)]) in + return helper.update(entries: entries, invalidateEntries: invalidateEntries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenAction(postbox: postbox, type: .consumeUnseenPersonalMessage, id: entry.id, { transaction, entry -> Signal in + if let entry = entry { + if let _ = entry.action as? ConsumePersonalMessageAction { + return synchronizeConsumeMessageContents(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: entry.id, action: nil) + }) + + disposable.set(signal.start()) + } + + for (entry, disposable) in beginValidateOperations { + let signal = synchronizeUnseenPersonalMentionsTag(postbox: postbox, network: network, entry: entry) + |> then(postbox.transaction { transaction -> Void in + transaction.removeInvalidatedMessageHistoryTagsSummaryEntry(entry) + }) + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizeConsumeMessageContents(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal { + if id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup { + return network.request(Api.functions.messages.readMessageContents(id: [id.id])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } + return postbox.transaction { transaction -> Void in + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: nil) + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed { + attributes[j] = ConsumablePersonalMentionMessageAttribute(consumed: true, pending: false) + break loop + } + } + var updatedTags = currentMessage.tags + updatedTags.remove(.unseenPersonalMessage) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + } else if id.peerId.namespace == Namespaces.Peer.CloudChannel { + if let peer = transaction.getPeer(id.peerId), let inputChannel = apiInputChannel(peer) { + return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: [id.id])) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: nil) + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed { + attributes[j] = ConsumablePersonalMentionMessageAttribute(consumed: true, pending: false) + break loop + } + } + var updatedTags = currentMessage.tags + updatedTags.remove(.unseenPersonalMessage) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + } else { + return .complete() + } + } else { + return .complete() + } +} + +private func synchronizeUnseenPersonalMentionsTag(postbox: Postbox, network: Network, entry: InvalidatedMessageHistoryTagsSummaryEntry) -> Signal { + return postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(entry.key.peerId), let inputPeer = apiInputPeer(peer) { + return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeer(peer: inputPeer)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .peerDialogs(dialogs, _, _, _, _): + if let dialog = dialogs.filter({ $0.peerId == entry.key.peerId }).first { + let apiTopMessage: Int32 + let apiUnreadMentionsCount: Int32 + switch dialog { + case let .dialog(_, _, topMessage, _, _, _, unreadMentionsCount, _, _, _, _): + apiTopMessage = topMessage + apiUnreadMentionsCount = unreadMentionsCount + + case .dialogFolder: + assertionFailure() + return .complete() + } + + return postbox.transaction { transaction -> Void in + transaction.replaceMessageTagSummary(peerId: entry.key.peerId, tagMask: entry.key.tagMask, namespace: entry.key.namespace, count: apiUnreadMentionsCount, maxId: apiTopMessage) + } + } else { + return .complete() + } + } + } else { + return .complete() + } + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedGlobalNotificationSettings.swift b/submodules/TelegramCore/TelegramCore/ManagedGlobalNotificationSettings.swift new file mode 100644 index 0000000000..036e9518c7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedGlobalNotificationSettings.swift @@ -0,0 +1,213 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func updateGlobalNotificationSettingsInteractively(postbox: Postbox, _ f: @escaping (GlobalNotificationSettingsSet) -> GlobalNotificationSettingsSet) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + if let current = current as? GlobalNotificationSettings { + return GlobalNotificationSettings(toBeSynchronized: f(current.effective), remote: current.remote) + } else { + let settings = f(GlobalNotificationSettingsSet.defaultSettings) + return GlobalNotificationSettings(toBeSynchronized: settings, remote: settings) + } + }) + } +} + +public func resetPeerNotificationSettings(network: Network) -> Signal { + return network.request(Api.functions.account.resetNotifySettings()) + |> retryRequest + |> mapToSignal { _ in return Signal.complete() } +} + +private enum SynchronizeGlobalSettingsData: Equatable { + case none + case fetch + case push(GlobalNotificationSettingsSet) + + static func ==(lhs: SynchronizeGlobalSettingsData, rhs: SynchronizeGlobalSettingsData) -> Bool { + switch lhs { + case .none: + if case .none = rhs { + return true + } else { + return false + } + case .fetch: + if case .fetch = rhs { + return true + } else { + return false + } + case let .push(settings): + if case .push(settings) = rhs { + return true + } else { + return false + } + } + } +} + +func managedGlobalNotificationSettings(postbox: Postbox, network: Network) -> Signal { + let data = postbox.preferencesView(keys: [PreferencesKeys.globalNotifications]) + |> map { view -> SynchronizeGlobalSettingsData in + if let preferences = view.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = preferences.toBeSynchronized { + return .push(settings) + } else { + return .none + } + } else { + return .fetch + } + } + let action = data + |> distinctUntilChanged + |> mapToSignal { data -> Signal in + switch data { + case .none: + return .complete() + case .fetch: + return fetchedNotificationSettings(network: network) + |> mapToSignal { settings -> Signal in + return postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + if let current = current as? GlobalNotificationSettings { + return GlobalNotificationSettings(toBeSynchronized: current.toBeSynchronized, remote: settings) + } else { + return GlobalNotificationSettings(toBeSynchronized: nil, remote: settings) + } + }) + } + } + case let .push(settings): + return pushedNotificationSettings(network: network, settings: settings) + |> then(postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: PreferencesKeys.globalNotifications, { current in + if let current = current as? GlobalNotificationSettings, current.toBeSynchronized == settings { + return GlobalNotificationSettings(toBeSynchronized: nil, remote: settings) + } else { + return current + } + }) + }) + } + } + + return action +} + +private func fetchedNotificationSettings(network: Network) -> Signal { + let chats = network.request(Api.functions.account.getNotifySettings(peer: Api.InputNotifyPeer.inputNotifyChats)) + let users = network.request(Api.functions.account.getNotifySettings(peer: Api.InputNotifyPeer.inputNotifyUsers)) + let channels = network.request(Api.functions.account.getNotifySettings(peer: Api.InputNotifyPeer.inputNotifyBroadcasts)) + let contactsJoinedMuted = network.request(Api.functions.account.getContactSignUpNotification()) + + return combineLatest(chats, users, channels, contactsJoinedMuted) + |> retryRequest + |> map { chats, users, channels, contactsJoinedMuted in + let chatsSettings: MessageNotificationSettings + switch chats { + case .peerNotifySettingsEmpty: + chatsSettings = MessageNotificationSettings.defaultSettings + case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + chatsSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + } + + let userSettings: MessageNotificationSettings + switch users { + case .peerNotifySettingsEmpty: + userSettings = MessageNotificationSettings.defaultSettings + case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + userSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + } + + let channelSettings: MessageNotificationSettings + switch channels { + case .peerNotifySettingsEmpty: + channelSettings = MessageNotificationSettings.defaultSettings + case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + channelSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + } + + return GlobalNotificationSettingsSet(privateChats: userSettings, groupChats: chatsSettings, channels: channelSettings, contactsJoined: contactsJoinedMuted == .boolFalse) + } +} + +private func apiInputPeerNotifySettings(_ settings: MessageNotificationSettings) -> Api.InputPeerNotifySettings { + let muteUntil: Int32? + if settings.enabled { + muteUntil = 0 + } else { + muteUntil = Int32.max + } + let sound: String? = settings.sound.apiSound + var flags: Int32 = 0 + flags |= (1 << 0) + if muteUntil != nil { + flags |= (1 << 2) + } + if sound != nil { + flags |= (1 << 3) + } + return .inputPeerNotifySettings(flags: flags, showPreviews: settings.displayPreviews ? .boolTrue : .boolFalse, silent: nil, muteUntil: muteUntil, sound: sound) +} + +private func pushedNotificationSettings(network: Network, settings: GlobalNotificationSettingsSet) -> Signal { + let pushedChats = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyChats, settings: apiInputPeerNotifySettings(settings.groupChats))) + let pushedUsers = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyUsers, settings: apiInputPeerNotifySettings(settings.privateChats))) + let pushedChannels = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyBroadcasts, settings: apiInputPeerNotifySettings(settings.channels))) + let pushedContactsJoined = network.request(Api.functions.account.setContactSignUpNotification(silent: settings.contactsJoined ? .boolFalse : .boolTrue)) + return combineLatest(pushedChats, pushedUsers, pushedChannels, pushedContactsJoined) + |> retryRequest + |> mapToSignal { _ -> Signal in return .complete() } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedLocalInputActivities.swift b/submodules/TelegramCore/TelegramCore/ManagedLocalInputActivities.swift new file mode 100644 index 0000000000..61b719b382 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedLocalInputActivities.swift @@ -0,0 +1,154 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +struct PeerInputActivityRecord: Equatable { + let activity: PeerInputActivity + let updateId: Int32 +} + +private final class ManagedLocalTypingActivitiesContext { + private var disposables: [PeerId: (PeerInputActivityRecord, MetaDisposable)] = [:] + + func update(activities: [PeerId: [PeerId: PeerInputActivityRecord]]) -> (start: [(PeerId, PeerInputActivityRecord?, MetaDisposable)], dispose: [MetaDisposable]) { + var start: [(PeerId, PeerInputActivityRecord?, MetaDisposable)] = [] + var dispose: [MetaDisposable] = [] + + var validPeerIds = Set() + for (peerId, record) in activities { + if let activity = record.values.first { + validPeerIds.insert(peerId) + + let currentRecord = self.disposables[peerId] + if currentRecord == nil || currentRecord!.0 != activity { + if let disposable = currentRecord?.1 { + dispose.append(disposable) + } + + let disposable = MetaDisposable() + start.append((peerId, activity, disposable)) + + self.disposables[peerId] = (activity, disposable) + } + } + } + + var removePeerIds: [PeerId] = [] + for key in self.disposables.keys { + if !validPeerIds.contains(key) { + removePeerIds.append(key) + } + } + + for peerId in removePeerIds { + dispose.append(self.disposables[peerId]!.1) + self.disposables.removeValue(forKey: peerId) + } + + return (start, dispose) + } + + func dispose() { + for (_, record) in self.disposables { + record.1.dispose() + } + self.disposables.removeAll() + } +} + +func managedLocalTypingActivities(activities: Signal<[PeerId: [PeerId: PeerInputActivityRecord]], NoError>, postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal { + return Signal { subscriber in + let context = Atomic(value: ManagedLocalTypingActivitiesContext()) + let disposable = activities.start(next: { activities in + let (start, dispose) = context.with { context in + return context.update(activities: activities) + } + + for disposable in dispose { + disposable.dispose() + } + + for (peerId, activity, disposable) in start { + disposable.set(requestActivity(postbox: postbox, network: network, accountPeerId: accountPeerId, peerId: peerId, activity: activity?.activity).start()) + } + }) + return ActionDisposable { + disposable.dispose() + + context.with { context -> Void in + context.dispose() + } + } + } +} + +private func actionFromActivity(_ activity: PeerInputActivity?) -> Api.SendMessageAction { + if let activity = activity { + switch activity { + case .typingText: + return .sendMessageTypingAction + case .recordingVoice: + return .sendMessageRecordAudioAction + case .playingGame: + return .sendMessageGamePlayAction + case let .uploadingFile(progress): + return .sendMessageUploadDocumentAction(progress: progress) + case let .uploadingPhoto(progress): + return .sendMessageUploadPhotoAction(progress: progress) + case let .uploadingVideo(progress): + return .sendMessageUploadVideoAction(progress: progress) + case .recordingInstantVideo: + return .sendMessageRecordRoundAction + case let .uploadingInstantVideo(progress): + return .sendMessageUploadRoundAction(progress: progress) + } + } else { + return .sendMessageCancelAction + } +} + +private func requestActivity(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, activity: PeerInputActivity?) -> Signal { + return postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if peerId == accountPeerId { + return .complete() + } + if let channel = peer as? TelegramChannel, case .broadcast = channel.info { + return .complete() + } + + if let inputPeer = apiInputPeer(peer) { + return network.request(Api.functions.messages.setTyping(peer: inputPeer, action: actionFromActivity(activity))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else if let peer = peer as? TelegramSecretChat, activity == .typingText { + return network.request(Api.functions.messages.setEncryptedTyping(peer: .inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash), typing: .boolTrue)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedLocalizationUpdatesOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedLocalizationUpdatesOperations.swift new file mode 100644 index 0000000000..cc5e2378c8 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedLocalizationUpdatesOperations.swift @@ -0,0 +1,311 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedLocalizationUpdatesOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeLocalizationUpdatesOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedLocalizationUpdatesOperations(accountManager: AccountManager, postbox: Postbox, network: Network) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeLocalizationUpdates + + let helper = Atomic(value: ManagedLocalizationUpdatesOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let _ = entry.contents as? SynchronizeLocalizationUpdatesOperation { + return synchronizeLocalizationUpdates(accountManager: accountManager, postbox: postbox, network: network) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private enum SynchronizeLocalizationUpdatesError { + case done + case reset +} + +func getLocalization(_ transaction: AccountManagerModifier) -> (primary: (code: String, version: Int32, entries: [LocalizationEntry]), secondary: (code: String, version: Int32, entries: [LocalizationEntry])?) { + let localizationSettings: LocalizationSettings? + if let current = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings { + localizationSettings = current + } else { + localizationSettings = nil + } + if let localizationSettings = localizationSettings { + return (primary: (localizationSettings.primaryComponent.languageCode, localizationSettings.primaryComponent.localization.version, localizationSettings.primaryComponent.localization.entries), secondary: localizationSettings.secondaryComponent.flatMap({ ($0.languageCode, $0.localization.version, $0.localization.entries) })) + } else { + return (primary: ("en", 0, []), secondary: nil) + } +} + +private func parseLangPackDifference(_ difference: Api.LangPackDifference) -> (code: String, fromVersion: Int32, version: Int32, entries: [LocalizationEntry]) { + switch difference { + case let .langPackDifference(code, fromVersion, version, strings): + var entries: [LocalizationEntry] = [] + for string in strings { + switch string { + case let .langPackString(key, value): + entries.append(.string(key: key, value: value)) + case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): + entries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) + case let .langPackStringDeleted(key): + entries.append(.string(key: key, value: "")) + } + } + return (code, fromVersion, version, entries) + } +} + +private func synchronizeLocalizationUpdates(accountManager: AccountManager, postbox: Postbox, network: Network) -> Signal { + let currentLanguageAndVersion = accountManager.transaction { transaction -> (primary: (code: String, version: Int32), secondary: (code: String, version: Int32)?) in + let (primary, secondary) = getLocalization(transaction) + return ((primary.code, primary.version), secondary.flatMap({ ($0.code, $0.version) })) + } + + let poll = currentLanguageAndVersion + |> introduceError(SynchronizeLocalizationUpdatesError.self) + |> mapToSignal { (primary, secondary) -> Signal in + var differences: [Signal] = [] + differences.append(network.request(Api.functions.langpack.getDifference(langCode: primary.code, fromVersion: primary.version))) + if let secondary = secondary { + differences.append(network.request(Api.functions.langpack.getDifference(langCode: secondary.code, fromVersion: secondary.version))) + } + + return combineLatest(differences) + |> mapError { _ -> SynchronizeLocalizationUpdatesError in return .reset } + |> mapToSignal { differences -> Signal in + let parsedDifferences = differences.map(parseLangPackDifference) + return accountManager.transaction { transaction -> Signal in + let (primary, secondary) = getLocalization(transaction) + + var currentSettings = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localizedName: "English", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil) + + for difference in parsedDifferences { + let current: (isPrimary: Bool, entries: [LocalizationEntry]) + if difference.code == primary.code { + if primary.version != difference.fromVersion { + return .complete() + } + current = (true, primary.entries) + } else if let secondary = secondary, difference.code == secondary.code { + if secondary.version != difference.fromVersion { + return .complete() + } + current = (false, secondary.entries) + } else { + return .fail(.reset) + } + + var updatedEntryKeys = Set() + for entry in difference.entries { + updatedEntryKeys.insert(entry.key) + } + + var mergedEntries: [LocalizationEntry] = [] + for entry in current.entries { + if !updatedEntryKeys.contains(entry.key) { + mergedEntries.append(entry) + } + } + mergedEntries.append(contentsOf: difference.entries) + if current.isPrimary { + currentSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localizedName: currentSettings.primaryComponent.localizedName, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent) + } else if let currentSecondary = currentSettings.secondaryComponent { + currentSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localizedName: currentSecondary.localizedName, localization: Localization(version: difference.version, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode)) + } + } + + transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in + return currentSettings + }) + return .fail(.done) + } + |> mapError { _ -> SynchronizeLocalizationUpdatesError in + return .reset + } + |> switchToLatest + } + } + + return ((poll + |> `catch` { error -> Signal in + switch error { + case .done: + return .fail(Void()) + case .reset: + return accountManager.transaction { transaction -> Signal in + let (primary, _) = getLocalization(transaction) + return downloadAndApplyLocalization(accountManager: accountManager, postbox: postbox, network: network, languageCode: primary.code) + |> mapError { _ -> Void in + return Void() + } + } + |> introduceError(Void.self) + |> switchToLatest + } + }) |> restart) |> `catch` { _ -> Signal in + return .complete() + } +} + +func tryApplyingLanguageDifference(transaction: AccountManagerModifier, langCode: String, difference: Api.LangPackDifference) -> Bool { + let (primary, secondary) = getLocalization(transaction) + switch difference { + case let .langPackDifference(updatedCode, fromVersion, updatedVersion, strings): + var current: (isPrimary: Bool, version: Int32, entries: [LocalizationEntry])? + if updatedCode == primary.code { + current = (true, primary.version, primary.entries) + } else if let secondary = secondary, secondary.code == updatedCode { + current = (false, secondary.version, secondary.entries) + } + guard let (isPrimary, version, entries) = current else { + return false + } + guard fromVersion == version else { + return false + } + var updatedEntries: [LocalizationEntry] = [] + + for string in strings { + switch string { + case let .langPackString(key, value): + updatedEntries.append(.string(key: key, value: value)) + case let .langPackStringPluralized(_, key, zeroValue, oneValue, twoValue, fewValue, manyValue, otherValue): + updatedEntries.append(.pluralizedString(key: key, zero: zeroValue, one: oneValue, two: twoValue, few: fewValue, many: manyValue, other: otherValue)) + case let .langPackStringDeleted(key): + updatedEntries.append(.string(key: key, value: "")) + } + } + + var updatedEntryKeys = Set() + for entry in updatedEntries { + updatedEntryKeys.insert(entry.key) + } + + var mergedEntries: [LocalizationEntry] = [] + for entry in entries { + if !updatedEntryKeys.contains(entry.key) { + mergedEntries.append(entry) + } + } + mergedEntries.append(contentsOf: updatedEntries) + + let currentSettings = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings ?? LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: "en", localizedName: "English", localization: Localization(version: 0, entries: []), customPluralizationCode: nil), secondaryComponent: nil) + + var updatedSettings: LocalizationSettings + if isPrimary { + updatedSettings = LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: currentSettings.primaryComponent.languageCode, localizedName: currentSettings.primaryComponent.localizedName, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSettings.primaryComponent.customPluralizationCode), secondaryComponent: currentSettings.secondaryComponent) + } else if let currentSecondary = currentSettings.secondaryComponent { + updatedSettings = LocalizationSettings(primaryComponent: currentSettings.primaryComponent, secondaryComponent: LocalizationComponent(languageCode: currentSecondary.languageCode, localizedName: currentSecondary.localizedName, localization: Localization(version: updatedVersion, entries: mergedEntries), customPluralizationCode: currentSecondary.customPluralizationCode)) + } else { + assertionFailure() + return false + } + + transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in + return updatedSettings + }) + + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedMessageHistoryHoles.swift b/submodules/TelegramCore/TelegramCore/ManagedMessageHistoryHoles.swift new file mode 100644 index 0000000000..e4c4397184 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedMessageHistoryHoles.swift @@ -0,0 +1,72 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private final class ManagedMessageHistoryHolesState { + private var holeDisposables: [MessageHistoryHolesViewEntry: Disposable] = [:] + + func clearDisposables() -> [Disposable] { + let disposables = Array(self.holeDisposables.values) + self.holeDisposables.removeAll() + return disposables + } + + func update(entries: Set) -> (removed: [Disposable], added: [MessageHistoryHolesViewEntry: MetaDisposable]) { + var removed: [Disposable] = [] + var added: [MessageHistoryHolesViewEntry: MetaDisposable] = [:] + + for (entry, disposable) in self.holeDisposables { + if !entries.contains(entry) { + removed.append(disposable) + self.holeDisposables.removeValue(forKey: entry) + } + } + + for entry in entries { + if self.holeDisposables[entry] == nil { + let disposable = MetaDisposable() + self.holeDisposables[entry] = disposable + added[entry] = disposable + } + } + + return (removed, added) + } +} + +func managedMessageHistoryHoles(accountPeerId: PeerId, network: Network, postbox: Postbox) -> Signal { + return Signal { _ in + let state = Atomic(value: ManagedMessageHistoryHolesState()) + + let disposable = postbox.messageHistoryHolesView().start(next: { view in + let (removed, added) = state.with { state -> (removed: [Disposable], added: [MessageHistoryHolesViewEntry: MetaDisposable]) in + return state.update(entries: view.entries) + } + + for disposable in removed { + disposable.dispose() + } + + for (entry, disposable) in added { + switch entry.hole { + case let .peer(hole): + disposable.set(fetchMessageHistoryHole(accountPeerId: accountPeerId, source: .network(network), postbox: postbox, peerId: hole.peerId, namespace: hole.namespace, direction: entry.direction, space: entry.space).start()) + } + } + }) + + return ActionDisposable { + disposable.dispose() + for disposable in state.with({ state -> [Disposable] in + state.clearDisposables() + }) { + disposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedNotificationSettingsBehaviors.swift b/submodules/TelegramCore/TelegramCore/ManagedNotificationSettingsBehaviors.swift new file mode 100644 index 0000000000..828a4d46c4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedNotificationSettingsBehaviors.swift @@ -0,0 +1,39 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +func managedNotificationSettingsBehaviors(postbox: Postbox) -> Signal { + return postbox.combinedView(keys: [.peerNotificationSettingsBehaviorTimestampView]) + |> mapToSignal { views -> Signal in + guard let view = views.views[.peerNotificationSettingsBehaviorTimestampView] as? PeerNotificationSettingsBehaviorTimestampView else { + return .complete() + } + guard let earliestTimestamp = view.earliestTimestamp else { + return .complete() + } + + let checkSignal = postbox.transaction { transaction -> Void in + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + for (peerId, notificationSettings) in transaction.getPeerIdsAndNotificationSettingsWithBehaviorTimestampLessThanOrEqualTo(timestamp) { + if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { + if case let .muted(untilTimestamp) = notificationSettings.muteState, untilTimestamp <= timestamp { + transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings.withUpdatedMuteState(.unmuted)]) + } + } + } + } + |> ignoreValues + + let timeout = earliestTimestamp - Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + if timeout <= 0 { + return checkSignal + } else { + return checkSignal |> delay(Double(timeout), queue: .mainQueue()) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedPendingPeerNotificationSettings.swift b/submodules/TelegramCore/TelegramCore/ManagedPendingPeerNotificationSettings.swift new file mode 100644 index 0000000000..b85452c543 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedPendingPeerNotificationSettings.swift @@ -0,0 +1,162 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedPendingPeerNotificationSettingsHelper { + var operationDisposables: [PeerId: (PeerNotificationSettings, Disposable)] = [:] + + func update(entries: [PeerId: PeerNotificationSettings]) -> (disposeOperations: [Disposable], beginOperations: [(PeerId, PeerNotificationSettings, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerId, PeerNotificationSettings, MetaDisposable)] = [] + + var validIds = Set() + for (peerId, settings) in entries { + validIds.insert(peerId) + + if let (currentSettings, currentDisposable) = self.operationDisposables[peerId] { + if !currentSettings.isEqual(to: settings) { + disposeOperations.append(currentDisposable) + + let disposable = MetaDisposable() + beginOperations.append((peerId, settings, disposable)) + self.operationDisposables[peerId] = (settings, disposable) + } + } else { + let disposable = MetaDisposable() + beginOperations.append((peerId, settings, disposable)) + self.operationDisposables[peerId] = (settings, disposable) + } + } + + var removeIds: [PeerId] = [] + for (id, settingsAndDisposable) in self.operationDisposables { + if !validIds.contains(id) { + removeIds.append(id) + disposeOperations.append(settingsAndDisposable.1) + } + } + + for id in removeIds { + self.operationDisposables.removeValue(forKey: id) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values).map { $0.1 } + self.operationDisposables.removeAll() + return disposables + } +} + +func managedPendingPeerNotificationSettings(postbox: Postbox, network: Network) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedPendingPeerNotificationSettingsHelper()) + + let disposable = postbox.combinedView(keys: [.pendingPeerNotificationSettings]).start(next: { view in + var entries: [PeerId: PeerNotificationSettings] = [:] + if let v = view.views[.pendingPeerNotificationSettings] as? PendingPeerNotificationSettingsView { + entries = v.entries + } + + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerId, PeerNotificationSettings, MetaDisposable)]) in + return helper.update(entries: entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (peerId, settings, disposable) in beginOperations { + let signal = pushPeerNotificationSettings(postbox: postbox, network: network, peerId: peerId, settings: settings) + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: PeerId, settings: PeerNotificationSettings) -> Signal { + return postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + var notificationPeerId = peerId + if let associatedPeerId = peer.associatedPeerId { + notificationPeerId = associatedPeerId + } + + if let notificationPeer = transaction.getPeer(notificationPeerId), let inputPeer = apiInputPeer(notificationPeer), let settings = settings as? TelegramPeerNotificationSettings { + let showPreviews: Api.Bool? + switch settings.displayPreviews { + case .default: + showPreviews = nil + case .show: + showPreviews = .boolTrue + case .hide: + showPreviews = .boolFalse + } + let muteUntil: Int32? + switch settings.muteState { + case let .muted(until): + muteUntil = until + case .unmuted: + muteUntil = 0 + case .default: + muteUntil = nil + } + let sound: String? = settings.messageSound.apiSound + var flags: Int32 = 0 + if showPreviews != nil { + flags |= (1 << 0) + } + if muteUntil != nil { + flags |= (1 << 2) + } + if sound != nil { + flags |= (1 << 3) + } + let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound) + return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyPeer(peer: inputPeer), settings: inputSettings)) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + transaction.updateCurrentPeerNotificationSettings([notificationPeerId: settings]) + if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) { + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil) + } + } + } + } else { + if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) { + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil) + } + return .complete() + } + } else { + if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) { + transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil) + } + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedProxyInfoUpdates.swift b/submodules/TelegramCore/TelegramCore/ManagedProxyInfoUpdates.swift new file mode 100644 index 0000000000..6a1735bedc --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedProxyInfoUpdates.swift @@ -0,0 +1,106 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedProxyInfoUpdates(postbox: Postbox, network: Network, viewTracker: AccountViewTracker) -> Signal { + return Signal { subscriber in + let queue = Queue() + let update = network.contextProxyId + |> distinctUntilChanged + |> deliverOn(queue) + |> mapToSignal { value -> Signal in + if value != nil { + let appliedOnce: Signal = network.request(Api.functions.help.getProxyData()) + |> `catch` { _ -> Signal in + return .single(.proxyDataEmpty(expires: 10 * 60)) + } + |> mapToSignal { data -> Signal in + return postbox.transaction { transaction -> Void in + switch data { + case .proxyDataEmpty: + transaction.replaceAdditionalChatListItems([]) + case let .proxyDataPromo(_, peer, chats, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + var additionalChatListItems: [PeerId] = [] + if let channel = transaction.getPeer(peer.peerId) as? TelegramChannel { + additionalChatListItems.append(channel.id) + } + + transaction.replaceAdditionalChatListItems(additionalChatListItems) + } + } + } + + return (appliedOnce + |> then( + Signal.complete() + |> delay(10.0 * 60.0, queue: Queue.concurrentDefaultQueue())) + ) + |> restart + } else { + return postbox.transaction { transaction -> Void in + transaction.replaceAdditionalChatListItems([]) + } + } + } + + let updateDisposable = update.start() + + let poll = postbox.combinedView(keys: [.additionalChatListItems]) + |> map { views -> Set in + if let view = views.views[.additionalChatListItems] as? AdditionalChatListItemsView { + return view.items + } + return Set() + } + |> distinctUntilChanged + |> mapToSignal { items -> Signal in + return Signal { subscriber in + let disposables = DisposableSet() + for item in items { + disposables.add(viewTracker.polledChannel(peerId: item).start()) + } + + return ActionDisposable { + disposables.dispose() + } + } + } + + let pollDisposable = poll.start() + + return ActionDisposable { + updateDisposable.dispose() + pollDisposable.dispose() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedRecentStickers.swift b/submodules/TelegramCore/TelegramCore/ManagedRecentStickers.swift new file mode 100644 index 0000000000..a676e9e5be --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedRecentStickers.swift @@ -0,0 +1,124 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private func hashForIds(_ ids: [Int64]) -> Int32 { + var acc: UInt32 = 0 + + for id in ids { + let low = UInt32(UInt64(bitPattern: id) & (0xffffffff as UInt64)) + let high = UInt32((UInt64(bitPattern: id) >> 32) & (0xffffffff as UInt64)) + + acc = (acc &* 20261) &+ high + acc = (acc &* 20261) &+ low + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +private func managedRecentMedia(postbox: Postbox, network: Network, collectionId: Int32, reverseHashOrder: Bool, forceFetch: Bool, fetch: @escaping (Int32) -> Signal<[OrderedItemListEntry]?, NoError>) -> Signal { + return postbox.transaction { transaction -> Signal in + var itemIds = transaction.getOrderedListItemIds(collectionId: collectionId).map { + RecentMediaItemId($0).mediaId.id + } + if reverseHashOrder { + itemIds.reverse() + } + return fetch(forceFetch ? 0 : hashForIds(itemIds)) + |> mapToSignal { items in + if let items = items { + return postbox.transaction { transaction -> Void in + transaction.replaceOrderedItemListItems(collectionId: collectionId, items: items) + } + } else { + return .complete() + } + } + } |> switchToLatest +} + +func managedRecentStickers(postbox: Postbox, network: Network) -> Signal { + return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudRecentStickers, reverseHashOrder: false, forceFetch: false, fetch: { hash in + return network.request(Api.functions.messages.getRecentStickers(flags: 0, hash: hash)) + |> retryRequest + |> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in + switch result { + case .recentStickersNotModified: + return .single(nil) + case let .recentStickers(_, _, stickers, _): + var items: [OrderedItemListEntry] = [] + for sticker in stickers { + if let file = telegramMediaFileFromApiDocument(sticker), let id = file.id { + items.append(OrderedItemListEntry(id: RecentMediaItemId(id).rawValue, contents: RecentMediaItem(file))) + } + } + return .single(items) + } + } + }) +} + +func managedRecentGifs(postbox: Postbox, network: Network, forceFetch: Bool = false) -> Signal { + return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudRecentGifs, reverseHashOrder: false, forceFetch: forceFetch, fetch: { hash in + return network.request(Api.functions.messages.getSavedGifs(hash: hash)) + |> retryRequest + |> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in + switch result { + case .savedGifsNotModified: + return .single(nil) + case let .savedGifs(_, gifs): + var items: [OrderedItemListEntry] = [] + for gif in gifs { + if let file = telegramMediaFileFromApiDocument(gif), let id = file.id { + items.append(OrderedItemListEntry(id: RecentMediaItemId(id).rawValue, contents: RecentMediaItem(file))) + } + } + return .single(items) + } + } + }) +} + +func managedSavedStickers(postbox: Postbox, network: Network) -> Signal { + return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudSavedStickers, reverseHashOrder: true, forceFetch: false, fetch: { hash in + return network.request(Api.functions.messages.getFavedStickers(hash: hash)) + |> retryRequest + |> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in + switch result { + case .favedStickersNotModified: + return .single(nil) + case let .favedStickers(_, packs, stickers): + var fileStringRepresentations: [MediaId: [String]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if fileStringRepresentations[mediaId] == nil { + fileStringRepresentations[mediaId] = [text] + } else { + fileStringRepresentations[mediaId]!.append(text) + } + } + } + } + + var items: [OrderedItemListEntry] = [] + for sticker in stickers { + if let file = telegramMediaFileFromApiDocument(sticker), let id = file.id { + var stringRepresentations: [String] = [] + if let representations = fileStringRepresentations[id] { + stringRepresentations = representations + } + items.append(OrderedItemListEntry(id: RecentMediaItemId(id).rawValue, contents: SavedStickerItem(file: file, stringRepresentations: stringRepresentations))) + } + } + return .single(items) + } + } + }) +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSecretChatOutgoingOperations.swift new file mode 100644 index 0000000000..1b4945c3d0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSecretChatOutgoingOperations.swift @@ -0,0 +1,1406 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import UIKit +#endif + +func addSecretChatOutgoingOperation(transaction: Transaction, peerId: PeerId, operation: SecretChatOutgoingOperationContents, state: SecretChatState) -> SecretChatState { + var updatedState = state + switch updatedState.embeddedState { + case let .sequenceBasedLayer(sequenceState): + let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing) + let keyValidityOperationCanonicalIndex = sequenceState.canonicalIncomingOperationIndex(keyValidityOperationIndex) + if let key = state.keychain.latestKey(validForSequenceBasedCanonicalIndex: keyValidityOperationCanonicalIndex) { + updatedState = updatedState.withUpdatedKeychain(updatedState.keychain.withUpdatedKey(fingerprint: key.fingerprint, { key in + return key?.withIncrementedUseCount() + })) + } + default: + break + } + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: operation, mutable: true, delivered: false)) + return secretChatInitiateRekeySessionIfNeeded(transaction: transaction, peerId: peerId, state: updatedState) +} + +private final class ManagedSecretChatOutgoingOperationsHelper { + var operationDisposables: [Int32: (PeerMergedOperationLogEntry, Disposable)] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if let entryAndDisposable = self.operationDisposables[entry.mergedIndex] { + if let lhsOperation = entryAndDisposable.0.contents as? SecretChatOutgoingOperation, let rhsOperation = entry.contents as? SecretChatOutgoingOperation { + var lhsDelete = false + if case .deleteMessages = lhsOperation.contents { + lhsDelete = true + } + var rhsDelete = false + if case .deleteMessages = rhsOperation.contents { + rhsDelete = true + } + if lhsDelete != rhsDelete { + disposeOperations.append(entryAndDisposable.1) + self.operationDisposables.removeValue(forKey: entry.mergedIndex) + } + } + } + + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = (entry, disposable) + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, entryAndDisposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(entryAndDisposable.1) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables.map { $0.1 } + } +} + +private func takenImmutableOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32) -> Signal { + return postbox.transaction { transaction -> PeerMergedOperationLogEntry? in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, let operation = entry.contents as? SecretChatOutgoingOperation { + if operation.mutable { + let updatedContents = SecretChatOutgoingOperation(contents: operation.contents, mutable: false, delivered: operation.delivered) + result = entry.withUpdatedContents(updatedContents).mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .update(updatedContents)) + } else { + result = entry.mergedEntry! + } + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + return result + } +} + +func managedSecretChatOutgoingOperations(auxiliaryMethods: AccountAuxiliaryMethods, postbox: Postbox, network: Network) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedSecretChatOutgoingOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.SecretOutgoing, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = takenImmutableOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex) + |> mapToSignal { entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SecretChatOutgoingOperation { + switch operation.contents { + case let .initialHandshakeAccept(gA, accessHash, b): + return initialHandshakeAccept(postbox: postbox, network: network, peerId: entry.peerId, accessHash: accessHash, gA: gA, b: b, tagLocalIndex: entry.tagLocalIndex) + case let .sendMessage(layer, id, file): + return sendMessage(auxiliaryMethods: auxiliaryMethods, postbox: postbox, network: network, messageId: id, file: file, tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered, layer: layer) + case let .reportLayerSupport(layer, actionGloballyUniqueId, layerSupport): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .reportLayerSupport(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, layerSupport: layerSupport), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .deleteMessages(layer, actionGloballyUniqueId, globallyUniqueIds): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .deleteMessages(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, globallyUniqueIds: globallyUniqueIds), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .clearHistory(layer, actionGloballyUniqueId): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .clearHistory(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .pfsRequestKey(layer, actionGloballyUniqueId, rekeySessionId, a): + return pfsRequestKey(postbox: postbox, network: network, peerId: entry.peerId, layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId: rekeySessionId, a: a, tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .pfsCommitKey(layer, actionGloballyUniqueId, rekeySessionId, keyFingerprint): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .pfsCommitKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId: rekeySessionId, keyFingerprint: keyFingerprint), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .pfsAcceptKey(layer, actionGloballyUniqueId, rekeySessionId, gA, b): + return pfsAcceptKey(postbox: postbox, network: network, peerId: entry.peerId, layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId: rekeySessionId, gA: gA, b: b, tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .pfsAbortSession(layer, actionGloballyUniqueId, rekeySessionId): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .pfsAbortSession(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId: rekeySessionId), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .noop(layer, actionGloballyUniqueId): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .noop(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .readMessagesContent(layer, actionGloballyUniqueId, globallyUniqueIds): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .readMessageContents(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, globallyUniqueIds: globallyUniqueIds), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .setMessageAutoremoveTimeout(layer, actionGloballyUniqueId, timeout, messageId): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .setMessageAutoremoveTimeout(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, timeout: timeout, messageId: messageId), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .resendOperations(layer, actionGloballyUniqueId, fromSeqNo, toSeqNo): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .resendOperations(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, fromSeqNo: fromSeqNo, toSeqNo: toSeqNo), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .screenshotMessages(layer, actionGloballyUniqueId, globallyUniqueIds, messageId): + return sendServiceActionMessage(postbox: postbox, network: network, peerId: entry.peerId, action: .screenshotMessages(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, globallyUniqueIds: globallyUniqueIds, messageId: messageId), tagLocalIndex: entry.tagLocalIndex, wasDelivered: operation.delivered) + case let .terminate(reportSpam): + return requestTerminateSecretChat(postbox: postbox, network: network, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, reportSpam: reportSpam) + } + } else { + assertionFailure() + } + } + return .complete() + } + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + disposable.dispose() + + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + } + } +} + +private func initialHandshakeAccept(postbox: Postbox, network: Network, peerId: PeerId, accessHash: Int64, gA: MemoryBuffer, b: MemoryBuffer, tagLocalIndex: Int32) -> Signal { + return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + let p = config.p.makeData() + + if !MTCheckIsSafeGAOrB(gA.makeData(), p) { + return postbox.transaction { transaction -> Void in + let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) + assert(removed) + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var updatedState = state + updatedState = updatedState.withUpdatedEmbeddedState(.terminated) + transaction.setPeerChatState(peerId, state: updatedState) + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + updatePeers(transaction: transaction, peers: [peer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in + return updated + }) + } + } else { + assertionFailure() + } + } + } + + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + + let bData = b.makeData() + + let gb = MTExp(g, bData, p)! + + var key = MTExp(gA.makeData(), bData, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + let result = network.request(Api.functions.messages.acceptEncryption(peer: .inputEncryptedChat(chatId: peerId.id, accessHash: accessHash), gB: Buffer(data: gb), keyFingerprint: keyFingerprint)) + + let response = result + |> map { result -> Api.EncryptedChat? in + return result + } + |> `catch` { error -> Signal in + return .single(nil) + } + + return response + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) + assert(removed) + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var updatedState = state + updatedState = updatedState.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted), baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil))) + updatedState = updatedState.withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) + + var layer: SecretChatLayer? + switch updatedState.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + if let layer = layer { + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: layer, actionGloballyUniqueId: arc4random64(), layerSupport: 46), state: updatedState) + } + transaction.setPeerChatState(peerId, state: updatedState) + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + updatePeers(transaction: transaction, peers: [peer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in + return updated + }) + } + } else { + assertionFailure() + } + } + } + } +} + +private func pfsRequestKey(postbox: Postbox, network: Network, peerId: PeerId, layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, a: MemoryBuffer, tagLocalIndex: Int32, wasDelivered: Bool) -> Signal { + return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let aData = a.makeData() + let ga = MTExp(g, aData, p)! + + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if let rekeyState = sequenceState.rekeyState, case .requesting = rekeyState.data { + transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .requested(a: a, config: config)))))) + } + default: + break + } + } + return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsRequestKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gA: MemoryBuffer(data: ga)), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) + } + |> switchToLatest + } +} + +private func pfsAcceptKey(postbox: Postbox, network: Network, peerId: PeerId, layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, gA: MemoryBuffer, b: MemoryBuffer, tagLocalIndex: Int32, wasDelivered: Bool) -> Signal { + return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let bData = b.makeData() + + let gb = MTExp(g, bData, p)! + + var key = MTExp(gA.makeData(), bData, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if let rekeyState = sequenceState.rekeyState, case .accepting = rekeyState.data { + transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .accepted(key: MemoryBuffer(data: key), keyFingerprint: keyFingerprint)))))) + } + default: + break + } + } + return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsAcceptKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gB: MemoryBuffer(data: gb), keyFingerprint: keyFingerprint), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) + } + |> switchToLatest + } +} + +private enum BoxedDecryptedMessage { + case layer8(SecretApi8.DecryptedMessage) + case layer46(SecretApi46.DecryptedMessage) + case layer73(SecretApi73.DecryptedMessage) + + func serialize(_ buffer: Buffer, role: SecretChatRole, sequenceInfo: SecretChatOperationSequenceInfo?) { + switch self { + case let .layer8(message): + let _ = message.serialize(buffer, true) + case let .layer46(message): + buffer.appendInt32(0x1be31789) + let randomBytes = malloc(15)! + arc4random_buf(randomBytes, 15) + serializeBytes(Buffer(memory: randomBytes, size: 15, capacity: 15, freeWhenDone: false), buffer: buffer, boxed: false) + free(randomBytes) + buffer.appendInt32(46) + + if let sequenceInfo = sequenceInfo { + let inSeqNo = (sequenceInfo.topReceivedOperationIndex + 1) * 2 + (role == .creator ? 0 : 1) + let outSeqNo = sequenceInfo.operationIndex * 2 + (role == .creator ? 1 : 0) + buffer.appendInt32(inSeqNo) + buffer.appendInt32(outSeqNo) + } else { + buffer.appendInt32(0) + buffer.appendInt32(0) + assertionFailure() + } + + let _ = message.serialize(buffer, true) + case let .layer73(message): + buffer.appendInt32(0x1be31789) + let randomBytes = malloc(15)! + arc4random_buf(randomBytes, 15) + serializeBytes(Buffer(memory: randomBytes, size: 15, capacity: 15, freeWhenDone: false), buffer: buffer, boxed: false) + free(randomBytes) + buffer.appendInt32(73) + + if let sequenceInfo = sequenceInfo { + let inSeqNo = (sequenceInfo.topReceivedOperationIndex + 1) * 2 + (role == .creator ? 0 : 1) + let outSeqNo = sequenceInfo.operationIndex * 2 + (role == .creator ? 1 : 0) + buffer.appendInt32(inSeqNo) + buffer.appendInt32(outSeqNo) + } else { + buffer.appendInt32(0) + buffer.appendInt32(0) + assertionFailure() + } + + let _ = message.serialize(buffer, true) + } + } +} + +private enum SecretMessageAction { + case deleteMessages(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64]) + case screenshotMessages(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64], messageId: MessageId) + case clearHistory(layer: SecretChatLayer, actionGloballyUniqueId: Int64) + case resendOperations(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, fromSeqNo: Int32, toSeqNo: Int32) + case reportLayerSupport(layer: SecretChatLayer, actionGloballyUniqueId: Int64, layerSupport: Int32) + case pfsRequestKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, gA: MemoryBuffer) + case pfsAcceptKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, gB: MemoryBuffer, keyFingerprint: Int64) + case pfsAbortSession(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64) + case pfsCommitKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, keyFingerprint: Int64) + case noop(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64) + case readMessageContents(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64]) + case setMessageAutoremoveTimeout(layer: SecretChatLayer, actionGloballyUniqueId: Int64, timeout: Int32, messageId: MessageId) + + var globallyUniqueId: Int64 { + switch self { + case let .deleteMessages(_, actionGloballyUniqueId, _): + return actionGloballyUniqueId + case let .screenshotMessages(_, actionGloballyUniqueId, _, _): + return actionGloballyUniqueId + case let .clearHistory(_, actionGloballyUniqueId): + return actionGloballyUniqueId + case let .resendOperations(_, actionGloballyUniqueId, _, _): + return actionGloballyUniqueId + case let .reportLayerSupport(_, actionGloballyUniqueId, _): + return actionGloballyUniqueId + case let .pfsRequestKey(_, actionGloballyUniqueId, _, _): + return actionGloballyUniqueId + case let .pfsAcceptKey(_, actionGloballyUniqueId, _, _, _): + return actionGloballyUniqueId + case let .pfsAbortSession(_, actionGloballyUniqueId, _): + return actionGloballyUniqueId + case let .pfsCommitKey(_, actionGloballyUniqueId, _, _): + return actionGloballyUniqueId + case let .noop(_, actionGloballyUniqueId): + return actionGloballyUniqueId + case let .readMessageContents(_, actionGloballyUniqueId, _): + return actionGloballyUniqueId + case let .setMessageAutoremoveTimeout(_, actionGloballyUniqueId, _, _): + return actionGloballyUniqueId + } + } + + var messageId: MessageId? { + switch self { + case let .setMessageAutoremoveTimeout(_, _, _, messageId): + return messageId + case let .screenshotMessages(_, _, _, messageId): + return messageId + default: + return nil + } + } +} + +private func decryptedAttributes46(_ attributes: [TelegramMediaFileAttribute], transaction: Transaction) -> [SecretApi46.DocumentAttribute] { + var result: [SecretApi46.DocumentAttribute] = [] + for attribute in attributes { + switch attribute { + case let .FileName(fileName): + result.append(.documentAttributeFilename(fileName: fileName)) + case .Animated: + result.append(.documentAttributeAnimated) + case let .Sticker(displayText, packReference, _): + var stickerSet: SecretApi46.InputStickerSet = .inputStickerSetEmpty + if let packReference = packReference { + switch packReference { + case let .name(name): + stickerSet = .inputStickerSetShortName(shortName: name) + case .id: + if let (info, _, _) = cachedStickerPack(transaction: transaction, reference: packReference) { + stickerSet = .inputStickerSetShortName(shortName: info.shortName) + } + } + } + result.append(.documentAttributeSticker(alt: displayText, stickerset: stickerSet)) + case let .ImageSize(size): + result.append(.documentAttributeImageSize(w: Int32(size.width), h: Int32(size.height))) + case let .Video(duration, size, _): + result.append(.documentAttributeVideo(duration: Int32(duration), w: Int32(size.width), h: Int32(size.height))) + case let .Audio(isVoice, duration, title, performer, waveform): + var flags: Int32 = 0 + if isVoice { + flags |= (1 << 10) + } + if let _ = title { + flags |= Int32(1 << 0) + } + if let _ = performer { + flags |= Int32(1 << 1) + } + var waveformBuffer: Buffer? + if let waveform = waveform { + flags |= Int32(1 << 2) + waveformBuffer = Buffer(data: waveform.makeData()) + } + result.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) + case .HasLinkedStickers: + break + } + } + return result +} + +private func decryptedAttributes73(_ attributes: [TelegramMediaFileAttribute], transaction: Transaction) -> [SecretApi73.DocumentAttribute] { + var result: [SecretApi73.DocumentAttribute] = [] + for attribute in attributes { + switch attribute { + case let .FileName(fileName): + result.append(.documentAttributeFilename(fileName: fileName)) + case .Animated: + result.append(.documentAttributeAnimated) + case let .Sticker(displayText, packReference, _): + var stickerSet: SecretApi73.InputStickerSet = .inputStickerSetEmpty + if let packReference = packReference { + switch packReference { + case let .name(name): + stickerSet = .inputStickerSetShortName(shortName: name) + case .id: + if let (info, _, _) = cachedStickerPack(transaction: transaction, reference: packReference) { + stickerSet = .inputStickerSetShortName(shortName: info.shortName) + } + } + } + result.append(.documentAttributeSticker(alt: displayText, stickerset: stickerSet)) + case let .ImageSize(size): + result.append(.documentAttributeImageSize(w: Int32(size.width), h: Int32(size.height))) + case let .Video(duration, size, videoFlags): + var flags: Int32 = 0 + if videoFlags.contains(.instantRoundVideo) { + flags |= 1 << 0 + } + result.append(.documentAttributeVideo(flags: flags, duration: Int32(duration), w: Int32(size.width), h: Int32(size.height))) + case let .Audio(isVoice, duration, title, performer, waveform): + var flags: Int32 = 0 + if isVoice { + flags |= (1 << 10) + } + if let _ = title { + flags |= Int32(1 << 0) + } + if let _ = performer { + flags |= Int32(1 << 1) + } + var waveformBuffer: Buffer? + if let waveform = waveform { + flags |= Int32(1 << 2) + waveformBuffer = Buffer(data: waveform.makeData()) + } + result.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) + case .HasLinkedStickers: + break + } + } + return result +} + +private func decryptedEntities73(_ entities: [MessageTextEntity]?) -> [SecretApi73.MessageEntity]? { + guard let entities = entities else { + return nil + } + + var result: [SecretApi73.MessageEntity] = [] + for entity in entities { + switch entity.type { + case .Unknown: + break + case .Mention: + result.append(.messageEntityMention(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Hashtag: + result.append(.messageEntityHashtag(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .BotCommand: + result.append(.messageEntityBotCommand(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Url: + result.append(.messageEntityUrl(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Email: + result.append(.messageEntityEmail(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Bold: + result.append(.messageEntityBold(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Italic: + result.append(.messageEntityItalic(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Code: + result.append(.messageEntityCode(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .Pre: + result.append(.messageEntityPre(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count), language: "")) + case let .TextUrl(url): + result.append(.messageEntityTextUrl(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count), url: url)) + case .TextMention: + break + case .PhoneNumber: + break + case .Strikethrough: + break + case .BlockQuote: + break + case .Underline: + break + case .Custom: + break + } + } + return result +} + +private func boxedDecryptedMessage(transaction: Transaction, message: Message, globallyUniqueId: Int64, uploadedFile: SecretChatOutgoingFile?, thumbnailData: [MediaId: (CGSize, Data)], layer: SecretChatLayer) -> BoxedDecryptedMessage { + let media: Media? = message.media.first + var messageAutoremoveTimeout: Int32 = 0 + var replyGlobalId: Int64? = nil + var flags: Int32 = 0 + for attribute in message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + if let message = message.associatedMessages[attribute.messageId] { + replyGlobalId = message.globallyUniqueId + flags |= (1 << 3) + break + } + } + } + + var viaBotName: String? + var entities: [MessageTextEntity]? + + for attribute in message.attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + messageAutoremoveTimeout = attribute.timeout + } else if let attribute = attribute as? InlineBotMessageAttribute { + if let title = attribute.title { + viaBotName = title + } else if let peerId = attribute.peerId, let peer = transaction.getPeer(peerId), let addressName = peer.addressName { + viaBotName = addressName + } + } else if let attribute = attribute as? TextEntitiesMessageAttribute { + entities = attribute.entities + } + } + + if let media = media { + if let image = media as? TelegramMediaImage, let uploadedFile = uploadedFile, let largestRepresentation = largestImageRepresentation(image.representations) { + let thumbW: Int32 + let thumbH: Int32 + let thumb: Buffer + if let (thumbnailSize, data) = thumbnailData[image.imageId] { + thumbW = Int32(thumbnailSize.width) + thumbH = Int32(thumbnailSize.height) + thumb = Buffer(data: data) + } else { + thumbW = 90 + thumbH = 90 + thumb = Buffer() + } + + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + let decryptedMedia = SecretApi8.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: thumb, thumbW: thumbW, thumbH: thumbH, w: Int32(largestRepresentation.dimensions.width), h: Int32(largestRepresentation.dimensions.height), size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv)) + + return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: decryptedMedia)) + case .layer46: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedMedia = SecretApi46.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: thumb, thumbW: thumbW, thumbH: thumbH, w: Int32(largestRepresentation.dimensions.width), h: Int32(largestRepresentation.dimensions.height), size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv), caption: "") + flags |= (1 << 9) + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + case .layer73: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + let decryptedMedia = SecretApi73.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: thumb, thumbW: thumbW, thumbH: thumbH, w: Int32(largestRepresentation.dimensions.width), h: Int32(largestRepresentation.dimensions.height), size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv), caption: "") + flags |= (1 << 9) + if message.groupingKey != nil { + flags |= (1 << 17) + } + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } + } else if let file = media as? TelegramMediaFile { + let thumbW: Int32 + let thumbH: Int32 + let thumb: Buffer + if let (thumbnailSize, data) = thumbnailData[file.fileId] { + thumbW = Int32(thumbnailSize.width) + thumbH = Int32(thumbnailSize.height) + thumb = Buffer(data: data) + } else { + thumbW = 0 + thumbH = 0 + thumb = Buffer() + } + + switch layer { + case .layer8: + if let uploadedFile = uploadedFile { + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + let decryptedMedia = SecretApi8.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: thumb, thumbW: thumbW, thumbH: thumbH, fileName: file.fileName ?? "file", mimeType: file.mimeType, size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv)) + + return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: decryptedMedia)) + } + case .layer46: + var decryptedMedia: SecretApi46.DecryptedMessageMedia? + + if let uploadedFile = uploadedFile { + var voiceDuration: Int32? + for attribute in file.attributes { + if case let .Audio(isVoice, duration, _, _, _) = attribute { + if isVoice { + voiceDuration = Int32(duration) + } + break + } + } + + if let voiceDuration = voiceDuration { + decryptedMedia = SecretApi46.DecryptedMessageMedia.decryptedMessageMediaAudio(duration: voiceDuration, mimeType: file.mimeType, size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv)) + } else { + decryptedMedia = SecretApi46.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: thumb, thumbW: thumbW, thumbH: thumbH, mimeType: file.mimeType, size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv), attributes: decryptedAttributes46(file.attributes, transaction: transaction), caption: "") + } + } else { + if let resource = file.resource as? CloudDocumentMediaResource, let size = file.size { + let thumb: SecretApi46.PhotoSize + if let smallestRepresentation = smallestImageRepresentation(file.previewRepresentations), let thumbResource = smallestRepresentation.resource as? CloudFileMediaResource { + thumb = .photoSize(type: "s", location: .fileLocation(dcId: Int32(thumbResource.datacenterId), volumeId: thumbResource.volumeId, localId: thumbResource.localId, secret: thumbResource.secret), w: Int32(smallestRepresentation.dimensions.width), h: Int32(smallestRepresentation.dimensions.height), size: thumbResource.size.flatMap(Int32.init) ?? 0) + } else { + thumb = SecretApi46.PhotoSize.photoSizeEmpty(type: "s") + } + decryptedMedia = SecretApi46.DecryptedMessageMedia.decryptedMessageMediaExternalDocument(id: resource.fileId, accessHash: resource.accessHash, date: 0, mimeType: file.mimeType, size: Int32(size), thumb: thumb, dcId: Int32(resource.datacenterId), attributes: decryptedAttributes46(file.attributes, transaction: transaction)) + } + } + + if let decryptedMedia = decryptedMedia { + if let _ = viaBotName { + flags |= (1 << 11) + } + flags |= (1 << 9) + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + } + case .layer73: + var decryptedMedia: SecretApi73.DecryptedMessageMedia? + + if let uploadedFile = uploadedFile { + decryptedMedia = SecretApi73.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: thumb, thumbW: thumbW, thumbH: thumbH, mimeType: file.mimeType, size: uploadedFile.size, key: Buffer(data: uploadedFile.key.aesKey), iv: Buffer(data: uploadedFile.key.aesIv), attributes: decryptedAttributes73(file.attributes, transaction: transaction), caption: "") + } else { + if let resource = file.resource as? CloudDocumentMediaResource, let size = file.size { + let thumb: SecretApi73.PhotoSize + if let smallestRepresentation = smallestImageRepresentation(file.previewRepresentations), let thumbResource = smallestRepresentation.resource as? CloudFileMediaResource { + thumb = .photoSize(type: "s", location: .fileLocation(dcId: Int32(thumbResource.datacenterId), volumeId: thumbResource.volumeId, localId: thumbResource.localId, secret: thumbResource.secret), w: Int32(smallestRepresentation.dimensions.width), h: Int32(smallestRepresentation.dimensions.height), size: thumbResource.size.flatMap(Int32.init) ?? 0) + } else { + thumb = SecretApi73.PhotoSize.photoSizeEmpty(type: "s") + } + decryptedMedia = SecretApi73.DecryptedMessageMedia.decryptedMessageMediaExternalDocument(id: resource.fileId, accessHash: resource.accessHash, date: 0, mimeType: file.mimeType, size: Int32(size), thumb: thumb, dcId: Int32(resource.datacenterId), attributes: decryptedAttributes73(file.attributes, transaction: transaction)) + } + } + + if let decryptedMedia = decryptedMedia { + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + if message.groupingKey != nil { + flags |= (1 << 17) + } + flags |= (1 << 9) + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } + } + } else if let webpage = media as? TelegramMediaWebpage { + var url: String? + if case let .Loaded(content) = webpage.content { + url = content.url + } + + if let url = url, !url.isEmpty { + switch layer { + case .layer8: + break + case .layer46: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedMedia = SecretApi46.DecryptedMessageMedia.decryptedMessageMediaWebPage(url: url) + flags |= (1 << 9) + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + case .layer73: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + let decryptedMedia = SecretApi73.DecryptedMessageMedia.decryptedMessageMediaWebPage(url: url) + flags |= (1 << 9) + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } + } + } else if let location = media as? TelegramMediaMap { + switch layer { + case .layer8: + break + case .layer46: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedMedia: SecretApi46.DecryptedMessageMedia + flags |= (1 << 9) + if let venue = location.venue { + decryptedMedia = .decryptedMessageMediaVenue(lat: location.latitude, long: location.longitude, title: venue.title, address: venue.address ?? "", provider: venue.provider ?? "", venueId: venue.id ?? "") + } else { + decryptedMedia = .decryptedMessageMediaGeoPoint(lat: location.latitude, long: location.longitude) + } + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + case .layer73: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + + let decryptedMedia: SecretApi73.DecryptedMessageMedia + flags |= (1 << 9) + if let venue = location.venue { + decryptedMedia = .decryptedMessageMediaVenue(lat: location.latitude, long: location.longitude, title: venue.title, address: venue.address ?? "", provider: venue.provider ?? "", venueId: venue.id ?? "") + } else { + decryptedMedia = .decryptedMessageMediaGeoPoint(lat: location.latitude, long: location.longitude) + } + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } + } else if let contact = media as? TelegramMediaContact { + switch layer { + case .layer8: + break + case .layer46: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedMedia: SecretApi46.DecryptedMessageMedia = .decryptedMessageMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName, userId: 0) + flags |= (1 << 9) + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + case .layer73: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + + let decryptedMedia: SecretApi73.DecryptedMessageMedia = .decryptedMessageMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName, userId: 0) + flags |= (1 << 9) + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } + } + } + + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: .decryptedMessageMediaEmpty)) + case .layer46: + if let _ = viaBotName { + flags |= (1 << 11) + } + return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) + case .layer73: + if let _ = viaBotName { + flags |= (1 << 11) + } + let decryptedEntites = entities.flatMap(decryptedEntities73) + if let _ = decryptedEntites { + flags |= (1 << 7) + } + return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) + } +} + +private func boxedDecryptedSecretMessageAction(action: SecretMessageAction) -> BoxedDecryptedMessage { + switch action { + case let .deleteMessages(layer, actionGloballyUniqueId, globallyUniqueIds): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionDeleteMessages(randomIds: globallyUniqueIds))) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionDeleteMessages(randomIds: globallyUniqueIds))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionDeleteMessages(randomIds: globallyUniqueIds))) + } + case let .screenshotMessages(layer, actionGloballyUniqueId, globallyUniqueIds, _): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionScreenshotMessages(randomIds: globallyUniqueIds))) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionScreenshotMessages(randomIds: globallyUniqueIds))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionScreenshotMessages(randomIds: globallyUniqueIds))) + } + case let .clearHistory(layer, actionGloballyUniqueId): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionFlushHistory)) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionFlushHistory)) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionFlushHistory)) + } + case let .resendOperations(layer, actionGloballyUniqueId, fromSeqNo, toSeqNo): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionResend(startSeqNo: fromSeqNo, endSeqNo: toSeqNo))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionResend(startSeqNo: fromSeqNo, endSeqNo: toSeqNo))) + } + case let .reportLayerSupport(layer, actionGloballyUniqueId, layerSupport): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionNotifyLayer(layer: layerSupport))) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionNotifyLayer(layer: layerSupport))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionNotifyLayer(layer: layerSupport))) + } + case let .pfsRequestKey(layer, actionGloballyUniqueId, rekeySessionId, gA): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionRequestKey(exchangeId: rekeySessionId, gA: Buffer(buffer: gA)))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionRequestKey(exchangeId: rekeySessionId, gA: Buffer(buffer: gA)))) + } + case let .pfsAcceptKey(layer, actionGloballyUniqueId, rekeySessionId, gB, keyFingerprint): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionAcceptKey(exchangeId: rekeySessionId, gB: Buffer(buffer: gB), keyFingerprint: keyFingerprint))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionAcceptKey(exchangeId: rekeySessionId, gB: Buffer(buffer: gB), keyFingerprint: keyFingerprint))) + } + case let .pfsAbortSession(layer, actionGloballyUniqueId, rekeySessionId): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionAbortKey(exchangeId: rekeySessionId))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionAbortKey(exchangeId: rekeySessionId))) + } + case let .pfsCommitKey(layer, actionGloballyUniqueId, rekeySessionId, keyFingerprint): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionCommitKey(exchangeId: rekeySessionId, keyFingerprint: keyFingerprint))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionCommitKey(exchangeId: rekeySessionId, keyFingerprint: keyFingerprint))) + } + case let .noop(layer, actionGloballyUniqueId): + switch layer { + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionNoop)) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionNoop)) + } + case let .readMessageContents(layer, actionGloballyUniqueId, globallyUniqueIds): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionReadMessages(randomIds: globallyUniqueIds))) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionReadMessages(randomIds: globallyUniqueIds))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionReadMessages(randomIds: globallyUniqueIds))) + } + case let .setMessageAutoremoveTimeout(layer, actionGloballyUniqueId, timeout, _): + switch layer { + case .layer8: + let randomBytesData = malloc(15)! + arc4random_buf(randomBytesData, 15) + let randomBytes = Buffer(memory: randomBytesData, size: 15, capacity: 15, freeWhenDone: true) + + return .layer8(.decryptedMessageService(randomId: actionGloballyUniqueId, randomBytes: randomBytes, action: .decryptedMessageActionSetMessageTTL(ttlSeconds: timeout))) + case .layer46: + return .layer46(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionSetMessageTTL(ttlSeconds: timeout))) + case .layer73: + return .layer73(.decryptedMessageService(randomId: actionGloballyUniqueId, action: .decryptedMessageActionSetMessageTTL(ttlSeconds: timeout))) + } + } +} + +private func markOutgoingOperationAsCompleted(transaction: Transaction, peerId: PeerId, tagLocalIndex: Int32, forceRemove: Bool) { + var removeFromTagMergedIndexOnly = false + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if tagLocalIndex >= sequenceState.baseOutgoingOperationIndex { + removeFromTagMergedIndexOnly = true + } + default: + break + } + } + if removeFromTagMergedIndexOnly && !forceRemove { + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex, { entry in + if let operation = entry?.contents as? SecretChatOutgoingOperation { + return PeerOperationLogEntryUpdate(mergedIndex: .remove, contents: .update(operation.withUpdatedDelivered(true))) + } else { + assertionFailure() + return PeerOperationLogEntryUpdate(mergedIndex: .remove, contents: .none) + } + }) + } else { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) + } +} + +private func replaceOutgoingOperationWithEmptyMessage(transaction: Transaction, peerId: PeerId, tagLocalIndex: Int32, globallyUniqueId: Int64) { + var layer: SecretChatLayer? + let state = transaction.getPeerChatState(peerId) as? SecretChatState + if let state = state { + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + } + if let layer = layer { + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex, { entry in + if let _ = entry?.contents as? SecretChatOutgoingOperation { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .update(SecretChatOutgoingOperation(contents: SecretChatOutgoingOperationContents.deleteMessages(layer: layer, actionGloballyUniqueId: arc4random64(), globallyUniqueIds: [globallyUniqueId]), mutable: true, delivered: false))) + } else { + assertionFailure() + return PeerOperationLogEntryUpdate(mergedIndex: .remove, contents: .none) + } + }) + } else { + assertionFailure() + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) + } +} + +private func resourceThumbnailData(auxiliaryMethods: AccountAuxiliaryMethods, mediaBox: MediaBox, resource: MediaResource, mediaId: MediaId) -> Signal<(MediaId, CGSize, Data)?, NoError> { + return mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false)) + |> take(1) + |> map { data -> (MediaId, CGSize, Data)? in + if data.complete, let (mappedSize, mappedData) = auxiliaryMethods.prepareSecretThumbnailData(data) { + return (mediaId, mappedSize, mappedData) + } else { + return nil + } + } +} + +private func messageWithThumbnailData(auxiliaryMethods: AccountAuxiliaryMethods, mediaBox: MediaBox, message: Message) -> Signal<[MediaId: (CGSize, Data)], NoError> { + var signals: [Signal<(MediaId, CGSize, Data)?, NoError>] = [] + for media in message.media { + if let image = media as? TelegramMediaImage { + if let smallestRepresentation = smallestImageRepresentation(image.representations) { + signals.append(resourceThumbnailData(auxiliaryMethods: auxiliaryMethods, mediaBox: mediaBox, resource: smallestRepresentation.resource, mediaId: image.imageId)) + } + } else if let file = media as? TelegramMediaFile { + if let smallestRepresentation = smallestImageRepresentation(file.previewRepresentations) { + signals.append(resourceThumbnailData(auxiliaryMethods: auxiliaryMethods, mediaBox: mediaBox, resource: smallestRepresentation.resource, mediaId: file.fileId)) + } + } + } + return combineLatest(signals) + |> map { values in + var result: [MediaId: (CGSize, Data)] = [:] + for value in values { + if let value = value { + result[value.0] = (value.1, value.2) + } + } + return result + } +} + +private func sendMessage(auxiliaryMethods: AccountAuxiliaryMethods, postbox: Postbox, network: Network, messageId: MessageId, file: SecretChatOutgoingFile?, tagLocalIndex: Int32, wasDelivered: Bool, layer: SecretChatLayer) -> Signal { + return postbox.transaction { transaction -> Signal<[MediaId: (CGSize, Data)], NoError> in + if let message = transaction.getMessage(messageId) { + return messageWithThumbnailData(auxiliaryMethods: auxiliaryMethods, mediaBox: postbox.mediaBox, message: message) + } else { + return .single([:]) + } + } + |> switchToLatest + |> mapToSignal { thumbnailData -> Signal in + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(messageId.peerId) as? SecretChatState, let peer = transaction.getPeer(messageId.peerId) as? TelegramSecretChat { + if let message = transaction.getMessage(messageId), let globallyUniqueId = message.globallyUniqueId { + let decryptedMessage = boxedDecryptedMessage(transaction: transaction, message: message, globallyUniqueId: globallyUniqueId, uploadedFile: file, thumbnailData: thumbnailData, layer: layer) + return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: globallyUniqueId, file: file, asService: wasDelivered, wasDelivered: wasDelivered) + |> mapToSignal { result in + return postbox.transaction { transaction -> Void in + let forceRemove: Bool + switch result { + case .message: + forceRemove = false + case .error: + forceRemove = true + } + markOutgoingOperationAsCompleted(transaction: transaction, peerId: messageId.peerId, tagLocalIndex: tagLocalIndex, forceRemove: forceRemove) + + var timestamp = message.timestamp + var encryptedFile: SecretChatFileReference? + if case let .message(result) = result { + switch result { + case let .sentEncryptedMessage(date): + timestamp = date + case let .sentEncryptedFile(date, file): + timestamp = date + encryptedFile = SecretChatFileReference(file) + } + } + + transaction.offsetPendingMessagesTimestamps(lowerBound: message.id, excludeIds: Set([messageId]), timestamp: timestamp) + + transaction.updateMessage(message.id, update: { currentMessage in + var flags = StoreMessageFlags(currentMessage.flags) + if case .message = result { + flags.remove(.Unsent) + flags.remove(.Sending) + } else { + flags = [.Failed] + } + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + + var updatedMedia = currentMessage.media + + if let fromMedia = currentMessage.media.first, let encryptedFile = encryptedFile, let file = file { + var toMedia: Media? + if let fromMedia = fromMedia as? TelegramMediaFile { + let updatedFile = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: encryptedFile.id), partialReference: nil, resource: SecretFileMediaResource(fileId: encryptedFile.id, accessHash: encryptedFile.accessHash, containerSize: encryptedFile.size, decryptedSize: file.size, datacenterId: Int(encryptedFile.datacenterId), key: file.key), previewRepresentations: fromMedia.previewRepresentations, immediateThumbnailData: fromMedia.immediateThumbnailData, mimeType: fromMedia.mimeType, size: fromMedia.size, attributes: fromMedia.attributes) + toMedia = updatedFile + updatedMedia = [updatedFile] + } + + if let toMedia = toMedia { + applyMediaResourceChanges(from: fromMedia, to: toMedia, postbox: postbox) + } + } + + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia)) + }) + + maybeReadSecretOutgoingMessage(transaction: transaction, index: MessageIndex(id: message.id, timestamp: timestamp)) + + var sentStickers: [TelegramMediaFile] = [] + for media in message.media { + if let file = media as? TelegramMediaFile { + if file.isSticker { + sentStickers.append(file) + } + } + } + + for file in sentStickers { + addRecentlyUsedSticker(transaction: transaction, fileReference: .standalone(media: file)) + } + + if case .error(.chatCancelled) = result { + + } + } + } + } else { + replaceOutgoingOperationWithEmptyMessage(transaction: transaction, peerId: messageId.peerId, tagLocalIndex: tagLocalIndex, globallyUniqueId: arc4random64()) + deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [messageId]) + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest + } +} + +private func sendServiceActionMessage(postbox: Postbox, network: Network, peerId: PeerId, action: SecretMessageAction, tagLocalIndex: Int32, wasDelivered: Bool) -> Signal { + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + let decryptedMessage = boxedDecryptedSecretMessageAction(action: action) + return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: action.globallyUniqueId, file: nil, asService: true, wasDelivered: wasDelivered) + |> mapToSignal { result in + return postbox.transaction { transaction -> Void in + let forceRemove: Bool + switch result { + case .message: + forceRemove = false + case .error: + forceRemove = true + } + markOutgoingOperationAsCompleted(transaction: transaction, peerId: peerId, tagLocalIndex: tagLocalIndex, forceRemove: forceRemove) + if let messageId = action.messageId { + var resultTimestamp: Int32? + transaction.updateMessage(messageId, update: { currentMessage in + var flags = StoreMessageFlags(currentMessage.flags) + var timestamp = currentMessage.timestamp + if case let .message(result) = result { + switch result { + case let .sentEncryptedMessage(date): + timestamp = date + case let .sentEncryptedFile(date, _): + timestamp = date + } + flags.remove(.Unsent) + flags.remove(.Sending) + } else { + flags = [.Failed] + } + resultTimestamp = timestamp + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + + if let resultTimestamp = resultTimestamp { + maybeReadSecretOutgoingMessage(transaction: transaction, index: MessageIndex(id: messageId, timestamp: resultTimestamp)) + } + } + } + } + } else { + return .complete() + } + } + |> switchToLatest +} + +private enum SendBoxedDecryptedMessageError { + case chatCancelled + case generic +} + +private enum SendBoxedDecryptedMessageResult { + case message(Api.messages.SentEncryptedMessage) + case error(SendBoxedDecryptedMessageError) +} + +private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer: TelegramSecretChat, state: SecretChatState, operationIndex: Int32, decryptedMessage: BoxedDecryptedMessage, globallyUniqueId: Int64, file: SecretChatOutgoingFile?, asService: Bool, wasDelivered: Bool) -> Signal { + let payload = Buffer() + var sequenceInfo: SecretChatOperationSequenceInfo? + var maybeParameters: SecretChatEncryptionParameters? + + let mode: SecretChatEncryptionMode + switch decryptedMessage { + case .layer8, .layer46: + mode = .v1 + default: + mode = .v2(role: state.role) + } + + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + if let key = state.keychain.indefinitelyValidKey() { + maybeParameters = SecretChatEncryptionParameters(key: key, mode: mode) + } + case let .sequenceBasedLayer(sequenceState): + let topReceivedOperationIndex: Int32 + if let topProcessedCanonicalIncomingOperationIndex = sequenceState.topProcessedCanonicalIncomingOperationIndex { + topReceivedOperationIndex = topProcessedCanonicalIncomingOperationIndex + } else { + topReceivedOperationIndex = -1 + } + let canonicalOperationIndex = sequenceState.canonicalOutgoingOperationIndex(operationIndex) + if let key = state.keychain.latestKey(validForSequenceBasedCanonicalIndex: canonicalOperationIndex) { + maybeParameters = SecretChatEncryptionParameters(key: key, mode: mode) + } + Logger.shared.log("SecretChat", "sending message with index \(canonicalOperationIndex) key \(String(describing: maybeParameters?.key.fingerprint))") + sequenceInfo = SecretChatOperationSequenceInfo(topReceivedOperationIndex: topReceivedOperationIndex, operationIndex: canonicalOperationIndex) + } + + guard let parameters = maybeParameters else { + Logger.shared.log("SecretChat", "no valid key found") + return .single(.error(.chatCancelled)) + } + + decryptedMessage.serialize(payload, role: state.role, sequenceInfo: sequenceInfo) + let encryptedPayload = encryptedMessageContents(parameters: parameters, data: MemoryBuffer(payload)) + let sendMessage: Signal + let inputPeer = Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash) + + if asService { + let actionRandomId: Int64 + if wasDelivered { + actionRandomId = arc4random64() + } else { + actionRandomId = globallyUniqueId + } + sendMessage = network.request(Api.functions.messages.sendEncryptedService(peer: inputPeer, randomId: actionRandomId, data: Buffer(data: encryptedPayload))) + } else { + if let file = file { + sendMessage = network.request(Api.functions.messages.sendEncryptedFile(peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload), file: file.reference.apiInputFile)) + } else { + sendMessage = network.request(Api.functions.messages.sendEncrypted(peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload))) + } + } + return sendMessage + |> map { next -> SendBoxedDecryptedMessageResult in + return .message(next) + } + |> `catch` { error -> Signal in + if error.errorDescription == "ENCRYPTION_DECLINED" { + return .single(.error(.chatCancelled)) + } else { + return .single(.error(.generic)) + } + } +} + +private func requestTerminateSecretChat(postbox: Postbox, network: Network, peerId: PeerId, tagLocalIndex: Int32, reportSpam: Bool) -> Signal { + return network.request(Api.functions.messages.discardEncryption(chatId: peerId.id)) + |> map(Optional.init) + |> `catch` { _ in + return .single(nil) + } + |> mapToSignal { _ -> Signal in + if reportSpam { + return postbox.transaction { transaction -> TelegramSecretChat? in + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + return peer + } else { + return nil + } + } + |> mapToSignal { peer -> Signal in + if let peer = peer { + return network.request(Api.functions.messages.reportEncryptedSpam(peer: Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash))) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + if result != nil { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedSecretChatData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return current + } + }) + } + } + } + } else { + return .single(Void()) + } + } + } else { + return .single(Void()) + } + } + |> mapToSignal { _ -> Signal in + return postbox.transaction { transaction -> Void in + markOutgoingOperationAsCompleted(transaction: transaction, peerId: peerId, tagLocalIndex: tagLocalIndex, forceRemove: true) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedServiceViews.swift b/submodules/TelegramCore/TelegramCore/ManagedServiceViews.swift new file mode 100644 index 0000000000..93fd480cbc --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedServiceViews.swift @@ -0,0 +1,20 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +func managedServiceViews(accountPeerId: PeerId, network: Network, postbox: Postbox, stateManager: AccountStateManager, pendingMessageManager: PendingMessageManager) -> Signal { + return Signal { _ in + let disposable = DisposableSet() + disposable.add(managedMessageHistoryHoles(accountPeerId: accountPeerId, network: network, postbox: postbox).start()) + disposable.add(managedChatListHoles(network: network, postbox: postbox, accountPeerId: accountPeerId).start()) + disposable.add(managedSynchronizePeerReadStates(network: network, postbox: postbox, stateManager: stateManager).start()) + disposable.add(managedSynchronizeGroupMessageStats(network: network, postbox: postbox, stateManager: stateManager).start()) + + return disposable + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeAppLogEventsOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeAppLogEventsOperations.swift new file mode 100644 index 0000000000..94011ec2a6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeAppLogEventsOperations.swift @@ -0,0 +1,142 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeAppLogEventsOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeAppLogEventsOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeAppLogEventsOperations(postbox: Postbox, network: Network) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeAppLogEvents + + let helper = Atomic(value: ManagedSynchronizeAppLogEventsOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 50).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeAppLogEventsOperation { + return synchronizeAppLogEvents(transaction: transaction, postbox: postbox, network: network, operations: [operation]) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizeAppLogEvents(transaction: Transaction, postbox: Postbox, network: Network, operations: [SynchronizeAppLogEventsOperation]) -> Signal { + var events: [Api.InputAppEvent] = [] + for operation in operations { + switch operation.content { + case let .add(time, type, peerId, data): + if let data = apiJson(data) { + events.append(.inputAppEvent(time: time, type: type, peer: peerId?.toInt64() ?? 0, data: data)) + } + default: + break + } + } + + return network.request(Api.functions.help.saveAppLog(events: events)) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeChatInputStateOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeChatInputStateOperations.swift new file mode 100644 index 0000000000..fa98283cc4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeChatInputStateOperations.swift @@ -0,0 +1,159 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeChatInputStateOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + private let hasRunningOperations: ValuePromise + + init(hasRunningOperations: ValuePromise) { + self.hasRunningOperations = hasRunningOperations + } + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + self.hasRunningOperations.set(!self.operationDisposables.isEmpty) + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeChatInputStateOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeChatInputStateOperations(postbox: Postbox, network: Network) -> Signal { + return Signal { subscriber in + let hasRunningOperations = ValuePromise(false, ignoreRepeated: true) + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeChatInputStates + + let helper = Atomic(value: ManagedSynchronizeChatInputStateOperationsHelper(hasRunningOperations: hasRunningOperations)) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeChatInputStateOperation { + return synchronizeChatInputState(transaction: transaction, postbox: postbox, network: network, peerId: entry.peerId, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + let statusDisposable = hasRunningOperations.get().start(next: { value in + subscriber.putNext(value) + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + statusDisposable.dispose() + } + } +} + +private func synchronizeChatInputState(transaction: Transaction, postbox: Postbox, network: Network, peerId: PeerId, operation: SynchronizeChatInputStateOperation) -> Signal { + let inputState = (transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState)?.synchronizeableInputState + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + var flags: Int32 = 0 + if let inputState = inputState { + if inputState.replyToMessageId != nil { + flags |= (1 << 0) + } + if !inputState.entities.isEmpty { + flags |= (1 << 3) + } + } + return network.request(Api.functions.messages.saveDraft(flags: flags, replyToMsgId: inputState?.replyToMessageId?.id, peer: inputPeer, message: inputState?.text ?? "", entities: apiEntitiesFromMessageTextEntities(inputState?.entities ?? [], associatedPeers: SimpleDictionary()))) + |> delay(2.0, queue: Queue.concurrentDefaultQueue()) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift new file mode 100644 index 0000000000..f41961288c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift @@ -0,0 +1,152 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeConsumeMessageContentsOperationHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeConsumeMessageContentsOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeConsumeMessageContentOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedSynchronizeConsumeMessageContentsOperationHelper()) + + let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.SynchronizeConsumeMessageContents, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeConsumeMessageContentsOperation { + return synchronizeConsumeMessageContents(transaction: transaction, network: network, stateManager: stateManager, peerId: entry.peerId, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizeConsumeMessageContents(transaction: Transaction, network: Network, stateManager: AccountStateManager, peerId: PeerId, operation: SynchronizeConsumeMessageContentsOperation) -> Signal { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + return network.request(Api.functions.messages.readMessageContents(id: operation.messageIds.map { $0.id })) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } + return .complete() + } + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { + return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: operation.messageIds.map { $0.id })) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return .complete() + } + } else { + return .complete() + } + } else { + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeEmojiKeywordsOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeEmojiKeywordsOperations.swift new file mode 100644 index 0000000000..9eed6d065a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeEmojiKeywordsOperations.swift @@ -0,0 +1,230 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeEmojiKeywordsOperationHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SynchronizeEmojiKeywords, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeEmojiKeywordsOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeEmojiKeywordsOperations(postbox: Postbox, network: Network) -> Signal { + let tag = OperationLogTags.SynchronizeEmojiKeywords + return Signal { _ in + let helper = Atomic(value: ManagedSynchronizeEmojiKeywordsOperationHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeEmojiKeywordsOperation { + let collectionId = emojiKeywordColletionIdForCode(operation.inputLanguageCode) + return synchronizeEmojiKeywords(postbox: postbox, transaction: transaction, network: network, operation: operation, collectionId: collectionId) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func keywordCollectionItemId(_ keyword: String, inputLanguageCode: String) -> Int64 { + let namespace = HashFunctions.murMurHash32(inputLanguageCode) + let id = HashFunctions.murMurHash32(keyword) + return (Int64(namespace) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: id))) +} + +private func synchronizeEmojiKeywords(postbox: Postbox, transaction: Transaction, network: Network, operation: SynchronizeEmojiKeywordsOperation, collectionId: ItemCollectionId) -> Signal { + if let languageCode = operation.languageCode, let fromVersion = operation.fromVersion { + return network.request(Api.functions.messages.getEmojiKeywordsDifference(langCode: languageCode, fromVersion: fromVersion)) + |> retryRequest + |> mapToSignal { result -> Signal in + switch result { + case let .emojiKeywordsDifference(langCode, _, version, keywords): + if langCode == languageCode { + var itemsToAppend: [String: EmojiKeywordItem] = [:] + var itemsToSubtract: [String: EmojiKeywordItem] = [:] + for apiEmojiKeyword in keywords { + switch apiEmojiKeyword { + case let .emojiKeyword(keyword, emoticons): + let indexKeys = stringIndexTokens(keyword, transliteration: .none).map { $0.toMemoryBuffer() } + let item = EmojiKeywordItem(index: ItemCollectionItemIndex(index: 0, id: 0), collectionId: collectionId.id, keyword: keyword, emoticons: emoticons, indexKeys: indexKeys) + itemsToAppend[keyword] = item + case let .emojiKeywordDeleted(keyword, emoticons): + let item = EmojiKeywordItem(index: ItemCollectionItemIndex(index: 0, id: 0), collectionId: collectionId.id, keyword: keyword, emoticons: emoticons, indexKeys: []) + itemsToSubtract[keyword] = item + } + } + let info = EmojiKeywordCollectionInfo(languageCode: langCode, inputLanguageCode: operation.inputLanguageCode, version: version, timestamp: Int32(CFAbsoluteTimeGetCurrent())) + return postbox.transaction { transaction -> Void in + var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! EmojiKeywordCollectionInfo } + if let index = updatedInfos.index(where: { $0.id == info.id }) { + updatedInfos.remove(at: index) + } + updatedInfos.append(info) + + if fromVersion != version { + let currentItems = transaction.getItemCollectionItems(collectionId: collectionId) + var updatedItems: [EmojiKeywordItem] = [] + + var index: Int32 = 0 + for case let item as EmojiKeywordItem in currentItems { + var updatedEmoticons = item.emoticons + var existingEmoticons = Set(item.emoticons) + if let appendedItem = itemsToAppend[item.keyword] { + for emoticon in appendedItem.emoticons { + if !existingEmoticons.contains(emoticon) { + existingEmoticons.insert(emoticon) + updatedEmoticons.append(emoticon) + } + } + itemsToAppend.removeValue(forKey: item.keyword) + } + if let subtractedItem = itemsToSubtract[item.keyword] { + let substractedEmoticons = Set(subtractedItem.emoticons) + updatedEmoticons = updatedEmoticons.filter { !substractedEmoticons.contains($0) } + } + if !updatedEmoticons.isEmpty { + updatedItems.append(EmojiKeywordItem(index: ItemCollectionItemIndex(index: index, id: keywordCollectionItemId(item.keyword, inputLanguageCode: operation.inputLanguageCode)), collectionId: item.collectionId, keyword: item.keyword, emoticons: updatedEmoticons, indexKeys: item.indexKeys)) + index += 1 + } + } + + for (_, item) in itemsToAppend where !item.emoticons.isEmpty { + updatedItems.append(EmojiKeywordItem(index: ItemCollectionItemIndex(index: index, id: keywordCollectionItemId(item.keyword, inputLanguageCode: operation.inputLanguageCode)), collectionId: collectionId.id, keyword: item.keyword, emoticons: item.emoticons, indexKeys: item.indexKeys)) + index += 1 + } + + transaction.replaceItemCollectionItems(collectionId: info.id, items: updatedItems) + } + transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) }) + } + } else { + return postbox.transaction { transaction in + addSynchronizeEmojiKeywordsOperation(transaction: transaction, inputLanguageCode: operation.inputLanguageCode, languageCode: nil, fromVersion: nil) + } + } + } + } + } else { + return network.request(Api.functions.messages.getEmojiKeywords(langCode: operation.inputLanguageCode)) + |> retryRequest + |> mapToSignal { result -> Signal in + switch result { + case let .emojiKeywordsDifference(langCode, _, version, keywords): + var items: [EmojiKeywordItem] = [] + var index: Int32 = 0 + for apiEmojiKeyword in keywords { + if case let .emojiKeyword(keyword, emoticons) = apiEmojiKeyword, !emoticons.isEmpty { + let indexKeys = stringIndexTokens(keyword, transliteration: .none).map { $0.toMemoryBuffer() } + let item = EmojiKeywordItem(index: ItemCollectionItemIndex(index: index, id: keywordCollectionItemId(keyword, inputLanguageCode: operation.inputLanguageCode)), collectionId: collectionId.id, keyword: keyword, emoticons: emoticons, indexKeys: indexKeys) + items.append(item) + } + index += 1 + } + let info = EmojiKeywordCollectionInfo(languageCode: langCode, inputLanguageCode: operation.inputLanguageCode, version: version, timestamp: Int32(CFAbsoluteTimeGetCurrent())) + return postbox.transaction { transaction -> Void in + var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! EmojiKeywordCollectionInfo } + if let index = updatedInfos.index(where: { $0.id == info.id }) { + updatedInfos.remove(at: index) + } + updatedInfos.append(info) + + transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) }) + transaction.replaceItemCollectionItems(collectionId: info.id, items: items) + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift new file mode 100644 index 0000000000..0edd84fa94 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift @@ -0,0 +1,104 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +private final class ManagedSynchronizeGroupMessageStatsState { + private var synchronizeDisposables: [PeerGroupAndNamespace: Disposable] = [:] + + func clearDisposables() -> [Disposable] { + let disposables = Array(self.synchronizeDisposables.values) + self.synchronizeDisposables.removeAll() + return disposables + } + + func update(operations: Set) -> (removed: [Disposable], added: [(PeerGroupAndNamespace, MetaDisposable)]) { + var removed: [Disposable] = [] + var added: [(PeerGroupAndNamespace, MetaDisposable)] = [] + + for (groupAndNamespace, disposable) in self.synchronizeDisposables { + if !operations.contains(groupAndNamespace) { + removed.append(disposable) + self.synchronizeDisposables.removeValue(forKey: groupAndNamespace) + } + } + + for groupAndNamespace in operations { + if self.synchronizeDisposables[groupAndNamespace] == nil { + let disposable = MetaDisposable() + self.synchronizeDisposables[groupAndNamespace] = disposable + added.append((groupAndNamespace, disposable)) + } + } + + return (removed, added) + } +} + +func managedSynchronizeGroupMessageStats(network: Network, postbox: Postbox, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let state = Atomic(value: ManagedSynchronizeGroupMessageStatsState()) + + let disposable = postbox.combinedView(keys: [.synchronizeGroupMessageStats]).start(next: { views in + let (removed, added) = state.with { state -> (removed: [Disposable], added: [(PeerGroupAndNamespace, MetaDisposable)]) in + let view = views.views[.synchronizeGroupMessageStats] as? SynchronizeGroupMessageStatsView + return state.update(operations: view?.groupsAndNamespaces ?? Set()) + } + + for disposable in removed { + disposable.dispose() + } + + for (groupAndNamespace, disposable) in added { + let synchronizeOperation = synchronizeGroupMessageStats(postbox: postbox, network: network, groupId: groupAndNamespace.groupId, namespace: groupAndNamespace.namespace) + disposable.set(synchronizeOperation.start()) + } + }) + + return ActionDisposable { + disposable.dispose() + for disposable in state.with({ state -> [Disposable] in + state.clearDisposables() + }) { + disposable.dispose() + } + } + } +} + +private func synchronizeGroupMessageStats(postbox: Postbox, network: Network, groupId: PeerGroupId, namespace: MessageId.Namespace) -> Signal { + if namespace != Namespaces.Message.Cloud || groupId == .root { + return postbox.transaction { transaction in + transaction.confirmSynchronizedPeerGroupMessageStats(groupId: groupId, namespace: namespace) + } + } + + return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeerFolder(folderId: groupId.rawValue)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction in + if let result = result { + switch result { + case let .peerDialogs(peerDialogs): + for dialog in peerDialogs.dialogs { + switch dialog { + case let .dialogFolder(dialogFolder): + transaction.resetPeerGroupSummary(groupId: groupId, namespace: namespace, summary: PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: dialogFolder.unreadMutedMessagesCount, chatCount: dialogFolder.unreadMutedPeersCount))) + case .dialog: + assertionFailure() + break + } + } + } + } + transaction.confirmSynchronizedPeerGroupMessageStats(groupId: groupId, namespace: namespace) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupedPeersOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupedPeersOperations.swift new file mode 100644 index 0000000000..66e5620a80 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupedPeersOperations.swift @@ -0,0 +1,164 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeGroupedPeersOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var validMergedIndices = Set() + for entry in entries { + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperations(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndices: [Int32], _ f: @escaping (Transaction, [PeerMergedOperationLogEntry]) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: [PeerMergedOperationLogEntry] = [] + for tagLocalIndex in tagLocalIndices { + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeGroupedPeersOperation { + result.append(entry.mergedEntry!) + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + } + + return f(transaction, result) + } + |> switchToLatest +} + +func managedSynchronizeGroupedPeersOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeGroupedPeers + + let helper = Atomic(value: ManagedSynchronizeGroupedPeersOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 100).start(next: { view in + let (disposeOperations, sharedBeginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + var beginOperationsByPeerId: [PeerId: [(PeerMergedOperationLogEntry, MetaDisposable)]] = [:] + for (entry, disposable) in sharedBeginOperations { + if beginOperationsByPeerId[entry.peerId] == nil { + beginOperationsByPeerId[entry.peerId] = [] + } + beginOperationsByPeerId[entry.peerId]?.append((entry, disposable)) + } + + if !beginOperationsByPeerId.isEmpty { + for (peerId, peerOperations) in beginOperationsByPeerId { + let localIndices = Array(peerOperations.map({ $0.0.tagLocalIndex })) + let sharedDisposable = MetaDisposable() + for (_, disposable) in peerOperations { + disposable.set(sharedDisposable) + } + + let signal = withTakenOperations(postbox: postbox, peerId: peerId, tag: tag, tagLocalIndices: localIndices, { transaction, entries -> Signal in + if !entries.isEmpty { + let operations = entries.compactMap({ $0.contents as? SynchronizeGroupedPeersOperation }) + if !operations.isEmpty { + return synchronizeGroupedPeers(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, operations: operations) + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + for tagLocalIndex in localIndices { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex) + } + }) + + sharedDisposable.set(signal.start()) + } + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizeGroupedPeers(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, operations: [SynchronizeGroupedPeersOperation]) -> Signal { + if operations.isEmpty { + return .complete() + } + var folderPeers: [Api.InputFolderPeer] = [] + for operation in operations { + if let inputPeer = transaction.getPeer(operation.peerId).flatMap(apiInputPeer) { + folderPeers.append(.inputFolderPeer(peer: inputPeer, folderId: operation.groupId.rawValue)) + } + } + if folderPeers.isEmpty { + return .complete() + } + + return network.request(Api.functions.folders.editPeerFolders(folderPeers: folderPeers)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } +} + diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeInstalledStickerPacksOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeInstalledStickerPacksOperations.swift new file mode 100644 index 0000000000..d51cf62640 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeInstalledStickerPacksOperations.swift @@ -0,0 +1,515 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeInstalledStickerPacksOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeInstalledStickerPacksOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeInstalledStickerPacksOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager, namespace: SynchronizeInstalledStickerPacksOperationNamespace) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag + switch namespace { + case .stickers: + tag = OperationLogTags.SynchronizeInstalledStickerPacks + case .masks: + tag = OperationLogTags.SynchronizeInstalledMasks + } + + let helper = Atomic(value: ManagedSynchronizeInstalledStickerPacksOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeInstalledStickerPacksOperation { + return stateManager.pollStateUpdateCompletion() + |> mapToSignal { _ -> Signal in + return postbox.transaction { transaction -> Signal in + return synchronizeInstalledStickerPacks(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, namespace: namespace, operation: operation) + } + |> switchToLatest + } + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set((signal |> delay(2.0, queue: Queue.concurrentDefaultQueue())).start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func hashForStickerPackInfos(_ infos: [StickerPackCollectionInfo]) -> Int32 { + var acc: UInt32 = 0 + + for info in infos { + acc = UInt32(bitPattern: Int32(bitPattern: acc &* UInt32(20261)) &+ info.hash) + } + + return Int32(bitPattern: acc & 0x7FFFFFFF) +} + +private enum SynchronizeInstalledStickerPacksError { + case restart + case done +} + +private func fetchStickerPack(network: Network, info: StickerPackCollectionInfo) -> Signal<(ItemCollectionId, [ItemCollectionItem]), NoError> { + return network.request(Api.functions.messages.getStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) + |> map { result -> (ItemCollectionId, [ItemCollectionItem]) in + var items: [ItemCollectionItem] = [] + switch result { + case let .stickerSet(_, packs, documents): + var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + let key = ValueBoxKey(text).toMemoryBuffer() + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if indexKeysByFile[mediaId] == nil { + indexKeysByFile[mediaId] = [key] + } else { + indexKeysByFile[mediaId]!.append(key) + } + } + break + } + } + + for apiDocument in documents { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + let fileIndexKeys: [MemoryBuffer] + if let indexKeys = indexKeysByFile[id] { + fileIndexKeys = indexKeys + } else { + fileIndexKeys = [] + } + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys)) + } + } + break + } + return (info.id, items) + } + |> `catch` { _ -> Signal<(ItemCollectionId, [ItemCollectionItem]), NoError> in + return .single((info.id, [])) + } +} + +private func resolveStickerPacks(network: Network, remoteInfos: [ItemCollectionId: StickerPackCollectionInfo], localInfos: [ItemCollectionId: StickerPackCollectionInfo]) -> Signal<[ItemCollectionId: [ItemCollectionItem]], NoError> { + var signals: [Signal<(ItemCollectionId, [ItemCollectionItem]), NoError>] = [] + for (id, remoteInfo) in remoteInfos { + let localInfo = localInfos[id] + if localInfo == nil || localInfo!.hash != remoteInfo.hash { + signals.append(fetchStickerPack(network: network, info: remoteInfo)) + } + } + return combineLatest(signals) + |> map { result -> [ItemCollectionId: [ItemCollectionItem]] in + var dict: [ItemCollectionId: [ItemCollectionItem]] = [:] + for (id, items) in result { + dict[id] = items + } + return dict + } +} + +private func installRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal, NoError> { + var signals: [Signal, NoError>] = [] + for info in infos { + let install = network.request(Api.functions.messages.installStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash), archived: .boolFalse)) + |> map { result -> Set in + switch result { + case .stickerSetInstallResultSuccess: + return Set() + case let .stickerSetInstallResultArchive(archivedSets): + var archivedIds = Set() + for archivedSet in archivedSets { + switch archivedSet { + case let .stickerSetCovered(set, _): + archivedIds.insert(StickerPackCollectionInfo(apiSet: set, namespace: info.id.namespace).id) + case let .stickerSetMultiCovered(set, _): + archivedIds.insert(StickerPackCollectionInfo(apiSet: set, namespace: info.id.namespace).id) + } + } + return archivedIds + } + } + |> `catch` { _ -> Signal, NoError> in + return .single(Set()) + } + signals.append(install) + } + return combineLatest(signals) + |> map { idsSets -> Set in + var result = Set() + for ids in idsSets { + result.formUnion(ids) + } + return result + } +} + +private func removeRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal { + var signals: [Signal] = [] + for info in infos { + let remove = network.request(Api.functions.messages.uninstallStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + signals.append(remove) + } + return combineLatest(signals) |> map { _ in return Void() } +} + +private func archiveRemoteStickerPacks(network: Network, infos: [StickerPackCollectionInfo]) -> Signal { + var signals: [Signal] = [] + for info in infos { + let archive = network.request(Api.functions.messages.installStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash), archived: .boolTrue)) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + signals.append(archive) + } + return combineLatest(signals) |> map { _ in return Void() } +} + +private func reorderRemoteStickerPacks(network: Network, namespace: SynchronizeInstalledStickerPacksOperationNamespace, ids: [ItemCollectionId]) -> Signal { + var flags: Int32 = 0 + switch namespace { + case .stickers: + break + case .masks: + flags |= (1 << 0) + } + return network.request(Api.functions.messages.reorderStickerSets(flags: flags, order: ids.map { $0.id })) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +private func synchronizeInstalledStickerPacks(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, namespace: SynchronizeInstalledStickerPacksOperationNamespace, operation: SynchronizeInstalledStickerPacksOperation) -> Signal { + let collectionNamespace: ItemCollectionId.Namespace + switch namespace { + case .stickers: + collectionNamespace = Namespaces.ItemCollection.CloudStickerPacks + case .masks: + collectionNamespace = Namespaces.ItemCollection.CloudMaskPacks + } + + let localCollectionInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo } + let initialLocalHash = hashForStickerPackInfos(localCollectionInfos) + + let request: Signal + switch namespace { + case .stickers: + request = network.request(Api.functions.messages.getAllStickers(hash: initialLocalHash)) + case .masks: + request = network.request(Api.functions.messages.getMaskStickers(hash: initialLocalHash)) + } + + let sequence = request + |> retryRequest + |> mapError { _ -> SynchronizeInstalledStickerPacksError in + return .restart + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Signal in + let checkLocalCollectionInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo } + if checkLocalCollectionInfos != localCollectionInfos { + return .fail(.restart) + } + + let localInitialStateCollectionOrder = operation.previousPacks + let localInitialStateCollectionIds = Set(localInitialStateCollectionOrder) + + let localCollectionOrder = checkLocalCollectionInfos.map { $0.id } + let localCollectionIds = Set(localCollectionOrder) + + var remoteCollectionInfos: [StickerPackCollectionInfo] = [] + switch result { + case let .allStickers(_, sets): + for apiSet in sets { + let info = StickerPackCollectionInfo(apiSet: apiSet, namespace: collectionNamespace) + remoteCollectionInfos.append(info) + } + case .allStickersNotModified: + remoteCollectionInfos = checkLocalCollectionInfos + } + + let remoteCollectionOrder = remoteCollectionInfos.map { $0.id } + let remoteCollectionIds = Set(remoteCollectionOrder) + + var remoteInfos: [ItemCollectionId: StickerPackCollectionInfo] = [:] + for info in remoteCollectionInfos { + remoteInfos[info.id] = info + } + var localInfos: [ItemCollectionId: StickerPackCollectionInfo] = [:] + for info in checkLocalCollectionInfos { + localInfos[info.id] = info + } + + if localInitialStateCollectionOrder == localCollectionOrder { + if checkLocalCollectionInfos == remoteCollectionInfos { + return .fail(.done) + } else { + return resolveStickerPacks(network: network, remoteInfos: remoteInfos, localInfos: localInfos) + |> mapError { _ -> SynchronizeInstalledStickerPacksError in + return .restart + } + |> mapToSignal { replaceItems -> Signal in + return postbox.transaction { transaction -> Signal in + let storeSignal: Signal + if localCollectionIds.isEmpty { + var incrementalSignal = postbox.transaction { transaction -> Void in + transaction.replaceItemCollectionInfos(namespace: collectionNamespace, itemCollectionInfos: remoteCollectionInfos.map { ($0.id, $0) }) + for id in localCollectionIds.subtracting(remoteCollectionIds) { + transaction.replaceItemCollectionItems(collectionId: id, items: []) + } + } + for (id, items) in replaceItems { + let partSignal = postbox.transaction { transaction -> Void in + transaction.replaceItemCollectionItems(collectionId: id, items: items) + } + incrementalSignal = incrementalSignal + |> then( + partSignal + |> delay(0.01, queue: Queue.concurrentDefaultQueue()) + ) + } + storeSignal = incrementalSignal + } else { + storeSignal = postbox.transaction { transaction -> Void in + transaction.replaceItemCollectionInfos(namespace: collectionNamespace, itemCollectionInfos: remoteCollectionInfos.map { ($0.id, $0) }) + for (id, items) in replaceItems { + transaction.replaceItemCollectionItems(collectionId: id, items: items) + } + for id in localCollectionIds.subtracting(remoteCollectionIds) { + transaction.replaceItemCollectionItems(collectionId: id, items: []) + } + } + } + + return ( + storeSignal + |> mapError { _ -> SynchronizeInstalledStickerPacksError in return .restart + } + ) + |> then(.fail(.done)) + } + |> introduceError(SynchronizeInstalledStickerPacksError.self) + |> switchToLatest + } + } + } else { + let locallyRemovedCollectionIds = localInitialStateCollectionIds.subtracting(localCollectionIds) + let locallyAddedCollectionIds = localCollectionIds.subtracting(localInitialStateCollectionIds) + let remotelyAddedCollections = remoteCollectionInfos.filter { info in + return !locallyRemovedCollectionIds.contains(info.id) && !localCollectionIds.contains(info.id) + } + let remotelyRemovedCollectionIds = remoteCollectionIds.subtracting(localInitialStateCollectionIds).subtracting(locallyAddedCollectionIds) + + var resultingCollectionInfos: [StickerPackCollectionInfo] = [] + resultingCollectionInfos.append(contentsOf: remotelyAddedCollections) + resultingCollectionInfos.append(contentsOf: checkLocalCollectionInfos.filter { info in + return !remotelyRemovedCollectionIds.contains(info.id) + }) + + let resultingCollectionIds = Set(resultingCollectionInfos.map { $0.id }) + let removeRemoteCollectionIds = remoteCollectionIds.subtracting(resultingCollectionIds) + let addRemoteCollectionIds = resultingCollectionIds.subtracting(remoteCollectionIds) + + var removeRemoteCollectionInfos: [StickerPackCollectionInfo] = [] + for id in removeRemoteCollectionIds { + if let info = remoteInfos[id] { + removeRemoteCollectionInfos.append(info) + } else if let info = localInfos[id] { + removeRemoteCollectionInfos.append(info) + } + } + + var addRemoteCollectionInfos: [StickerPackCollectionInfo] = [] + for id in addRemoteCollectionIds { + if let info = remoteInfos[id] { + addRemoteCollectionInfos.append(info) + } else if let info = localInfos[id] { + addRemoteCollectionInfos.append(info) + } + } + + let infosToArchive = removeRemoteCollectionInfos.filter { info in + return operation.archivedPacks.contains(info.id) + } + let infosToRemove = removeRemoteCollectionInfos.filter { info in + return !operation.archivedPacks.contains(info.id) + } + + let archivedOrRemovedIds = (combineLatest(archiveRemoteStickerPacks(network: network, infos: infosToArchive), removeRemoteStickerPacks(network: network, infos: infosToRemove)) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(Signal.single(Void()))) + |> mapToSignal { _ -> Signal, NoError> in + return installRemoteStickerPacks(network: network, infos: addRemoteCollectionInfos) + |> mapToSignal { ids -> Signal, NoError> in + return (reorderRemoteStickerPacks(network: network, namespace: namespace, ids: resultingCollectionInfos.map({ $0.id }).filter({ !ids.contains($0) })) + |> then(Signal.single(Void()))) + |> map { _ -> Set in + return ids + } + } + } + + var resultingInfos: [ItemCollectionId: StickerPackCollectionInfo] = [:] + for info in resultingCollectionInfos { + resultingInfos[info.id] = info + } + let resolvedItems = resolveStickerPacks(network: network, remoteInfos: resultingInfos, localInfos: localInfos) + + return combineLatest(archivedOrRemovedIds, resolvedItems) + |> mapError { _ -> SynchronizeInstalledStickerPacksError in return .restart } + |> mapToSignal { archivedOrRemovedIds, replaceItems -> Signal in + return (postbox.transaction { transaction -> Signal in + let finalCheckLocalCollectionInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo } + if finalCheckLocalCollectionInfos != localCollectionInfos { + return .fail(.restart) + } + + transaction.replaceItemCollectionInfos(namespace: collectionNamespace, itemCollectionInfos: resultingCollectionInfos.filter({ info in + return !archivedOrRemovedIds.contains(info.id) + }).map({ ($0.id, $0) })) + for (id, items) in replaceItems { + if !archivedOrRemovedIds.contains(id) { + transaction.replaceItemCollectionItems(collectionId: id, items: items) + } + } + for id in localCollectionIds.subtracting(resultingCollectionIds).union(archivedOrRemovedIds) { + transaction.replaceItemCollectionItems(collectionId: id, items: []) + } + + return .complete() + } + |> mapError { _ -> SynchronizeInstalledStickerPacksError in + return .restart + }) + |> switchToLatest + |> then(.fail(.done)) + } + } + } |> mapError { _ -> SynchronizeInstalledStickerPacksError in return .restart } |> switchToLatest + } + return ((sequence + |> `catch` { error -> Signal in + switch error { + case .done: + return .fail(.done) + case .restart: + return .complete() + } + }) |> restart) |> `catch` { _ -> Signal in + return .complete() + } + +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift new file mode 100644 index 0000000000..c6b65ba12f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift @@ -0,0 +1,238 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeMarkAllUnseenPersonalMessagesOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeMarkAllUnseenPersonalMessagesOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkAllUnseenPersonalMessages + + let helper = Atomic(value: ManagedSynchronizeMarkAllUnseenPersonalMessagesOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeMarkAllUnseenPersonalMessagesOperation { + return synchronizeMarkAllUnseen(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, peerId: entry.peerId, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private enum GetUnseenIdsError { + case done + case error(MTRpcError) +} + +private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, operation: SynchronizeMarkAllUnseenPersonalMessagesOperation) -> Signal { + guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else { + return .complete() + } + let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) + let limit: Int32 = 100 + let oneOperation: (Int32) -> Signal = { maxId in + return network.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: maxId, addOffset: maxId == 0 ? 0 : -1, limit: limit, maxId: maxId == 0 ? 0 : (maxId + 1), minId: 1)) + |> mapToSignal { result -> Signal<[MessageId], MTRpcError> in + switch result { + case let .messages(messages, _, _): + return .single(messages.compactMap({ $0.id })) + case let .channelMessages(channelMessages): + return .single(channelMessages.messages.compactMap({ $0.id })) + case .messagesNotModified: + return .single([]) + case let .messagesSlice(messagesSlice): + return .single(messagesSlice.messages.compactMap({ $0.id })) + } + } + |> mapToSignal { ids -> Signal in + let filteredIds = ids.filter { $0.id <= operation.maxId } + if filteredIds.isEmpty { + return .single(ids.min()?.id) + } + if peerId.namespace == Namespaces.Peer.CloudChannel { + guard let inputChannel = inputChannel else { + return .single(nil) + } + return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: filteredIds.map { $0.id })) + |> map { result -> Int32? in + if ids.count < limit { + return nil + } else { + return ids.min()?.id + } + } + } else { + return network.request(Api.functions.messages.readMessageContents(id: filteredIds.map { $0.id })) + |> map { result -> Int32? in + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + if ids.count < limit { + return nil + } else { + return ids.min()?.id + } + } + } + } + } + let currentMaxId = Atomic(value: 0) + let loopOperations: Signal = ( + ( + deferred { + return oneOperation(currentMaxId.with { $0 }) + } + |> `catch` { error -> Signal in + return .fail(.error(error)) + } + ) + |> mapToSignal { resultId -> Signal in + if let resultId = resultId { + let _ = currentMaxId.swap(resultId) + return .complete() + } else { + return .fail(.done) + } + } + |> `catch` { error -> Signal in + switch error { + case .done, .error: + return .fail(error) + } + } + |> restart + ) + return loopOperations + |> `catch` { _ -> Signal in + return .complete() + } +} + +func markUnseenPersonalMessage(transaction: Transaction, id: MessageId, addSynchronizeAction: Bool) { + if let message = transaction.getMessage(id) { + var consume = false + inner: for attribute in message.attributes { + if let attribute = attribute as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed, !attribute.pending { + consume = true + break inner + } + } + if consume { + transaction.updateMessage(id, update: { currentMessage in + var attributes = currentMessage.attributes + loop: for j in 0 ..< attributes.count { + if let attribute = attributes[j] as? ConsumablePersonalMentionMessageAttribute { + attributes[j] = ConsumablePersonalMentionMessageAttribute(consumed: attribute.consumed, pending: true) + break loop + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + + if addSynchronizeAction { + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: ConsumePersonalMessageAction()) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift new file mode 100644 index 0000000000..588b42d49e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift @@ -0,0 +1,130 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeMarkFeaturedStickerPacksAsSeenOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeMarkFeaturedStickerPacksAsSeenOperations(postbox: Postbox, network: Network) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkFeaturedStickerPacksAsSeen + + let helper = Atomic(value: ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeMarkFeaturedStickerPacksAsSeenOperation { + return synchronizeMarkFeaturedStickerPacksAsSeen(transaction: transaction, postbox: postbox, network: network, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizeMarkFeaturedStickerPacksAsSeen(transaction: Transaction, postbox: Postbox, network: Network, operation: SynchronizeMarkFeaturedStickerPacksAsSeenOperation) -> Signal { + return network.request(Api.functions.messages.readFeaturedStickers(id: operation.ids.map { $0.id })) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizePeerReadStates.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizePeerReadStates.swift new file mode 100644 index 0000000000..1e0f2382d7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizePeerReadStates.swift @@ -0,0 +1,76 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private final class ManagedSynchronizePeerReadStatesState { + private var synchronizeDisposables: [PeerId: (PeerReadStateSynchronizationOperation, Disposable)] = [:] + + func clearDisposables() -> [Disposable] { + let disposables = Array(self.synchronizeDisposables.values.map({ $0.1 })) + self.synchronizeDisposables.removeAll() + return disposables + } + + func update(operations: [PeerId: PeerReadStateSynchronizationOperation]) -> (removed: [Disposable], added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)]) { + var removed: [Disposable] = [] + var added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)] = [] + + for (peerId, (operation, disposable)) in self.synchronizeDisposables { + if operations[peerId] != operation { + removed.append(disposable) + self.synchronizeDisposables.removeValue(forKey: peerId) + } + } + + for (peerId, operation) in operations { + if self.synchronizeDisposables[peerId] == nil { + let disposable = MetaDisposable() + self.synchronizeDisposables[peerId] = (operation, disposable) + added.append((peerId, operation, disposable)) + } + } + + return (removed, added) + } +} + +func managedSynchronizePeerReadStates(network: Network, postbox: Postbox, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let state = Atomic(value: ManagedSynchronizePeerReadStatesState()) + + let disposable = postbox.synchronizePeerReadStatesView().start(next: { view in + let (removed, added) = state.with { state -> (removed: [Disposable], added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)]) in + return state.update(operations: view.operations) + } + + for disposable in removed { + disposable.dispose() + } + + for (peerId, operation, disposable) in added { + let synchronizeOperation: Signal + switch operation { + case .Validate: + synchronizeOperation = synchronizePeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, push: false, validate: true) + case let .Push(_, thenSync): + synchronizeOperation = synchronizePeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, push: true, validate: thenSync) + } + disposable.set(synchronizeOperation.start()) + } + }) + + return ActionDisposable { + disposable.dispose() + for disposable in state.with({ state -> [Disposable] in + state.clearDisposables() + }) { + disposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizePinnedChatsOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizePinnedChatsOperations.swift new file mode 100644 index 0000000000..2bf09e2285 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizePinnedChatsOperations.swift @@ -0,0 +1,292 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizePinnedChatsOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizePinnedChatsOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizePinnedChatsOperations(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) -> Signal { + return Signal { _ in + let helper = Atomic(value: ManagedSynchronizePinnedChatsOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.SynchronizePinnedChats, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizePinnedChatsOperation { + return synchronizePinnedChats(transaction: transaction, postbox: postbox, network: network, accountPeerId: accountPeerId, stateManager: stateManager, groupId: PeerGroupId(rawValue: entry.peerId.id), operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set((signal |> delay(2.0, queue: Queue.concurrentDefaultQueue())).start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, groupId: PeerGroupId, operation: SynchronizePinnedChatsOperation) -> Signal { + let initialRemoteItemIds = operation.previousItemIds + let initialRemoteItemIdsWithoutSecretChats = initialRemoteItemIds.filter { item in + switch item { + case let .peer(peerId): + return peerId.namespace != Namespaces.Peer.SecretChat + default: + return true + } + } + let localItemIds = transaction.getPinnedItemIds(groupId: groupId) + let localItemIdsWithoutSecretChats = localItemIds.filter { item in + switch item { + case let .peer(peerId): + return peerId.namespace != Namespaces.Peer.SecretChat + default: + return true + } + } + + return network.request(Api.functions.messages.getPinnedDialogs(folderId: groupId.rawValue)) + |> retryRequest + |> mapToSignal { dialogs -> Signal in + var storeMessages: [StoreMessage] = [] + var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] + var chatStates: [PeerId: PeerChatState] = [:] + var notificationSettings: [PeerId: PeerNotificationSettings] = [:] + + var remoteItemIds: [PinnedItemId] = [] + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + + switch dialogs { + case let .peerDialogs(dialogs, messages, chats, users, _): + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + loop: for dialog in dialogs { + let apiPeer: Api.Peer + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiTopMessage: Int32 + let apiUnreadCount: Int32 + let apiMarkedUnread: Bool + var apiChannelPts: Int32? + let apiNotificationSettings: Api.PeerNotifySettings + switch dialog { + case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _, _): + apiPeer = peer + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + apiNotificationSettings = peerNotificationSettings + apiChannelPts = pts + case .dialogFolder: + //assertionFailure() + continue loop + } + + let peerId: PeerId + switch apiPeer { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + remoteItemIds.append(.peer(peerId)) + + if readStates[peerId] == nil { + readStates[peerId] = [:] + } + readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) + + if let apiChannelPts = apiChannelPts { + chatStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: nil) + } + + notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) + } + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + storeMessages.append(storeMessage) + } + } + } + + var resultingItemIds: [PinnedItemId] + if initialRemoteItemIds == localItemIds { + resultingItemIds = remoteItemIds + } else { + let locallyRemovedFromRemoteItemIds = Set(initialRemoteItemIdsWithoutSecretChats).subtracting(Set(localItemIdsWithoutSecretChats)) + let remotelyRemovedItemIds = Set(initialRemoteItemIdsWithoutSecretChats).subtracting(Set(remoteItemIds)) + + resultingItemIds = localItemIds.filter { !remotelyRemovedItemIds.contains($0) } + resultingItemIds.append(contentsOf: remoteItemIds.filter { !locallyRemovedFromRemoteItemIds.contains($0) && !resultingItemIds.contains($0) }) + } + + return postbox.transaction { transaction -> Signal in + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + transaction.setPinnedItemIds(groupId: groupId, itemIds: resultingItemIds) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + transaction.updateCurrentPeerNotificationSettings(notificationSettings) + + var allPeersWithMessages = Set() + for message in storeMessages { + if !allPeersWithMessages.contains(message.id.peerId) { + allPeersWithMessages.insert(message.id.peerId) + } + } + let _ = transaction.addMessages(storeMessages, location: .UpperHistoryBlock) + + transaction.resetIncomingReadStates(readStates) + + for (peerId, chatState) in chatStates { + if let chatState = chatState as? ChannelState { + if let _ = transaction.getPeerChatState(peerId) as? ChannelState { + // skip changing state + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } else { + transaction.setPeerChatState(peerId, state: chatState) + } + } + + if remoteItemIds == resultingItemIds { + return .complete() + } else { + var inputDialogPeers: [Api.InputDialogPeer] = [] + for itemId in resultingItemIds { + switch itemId { + case let .peer(peerId): + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + inputDialogPeers.append(Api.InputDialogPeer.inputDialogPeer(peer: inputPeer)) + } + } + } + + return network.request(Api.functions.messages.reorderPinnedDialogs(flags: 1 << 0, folderId: groupId.rawValue, order: inputDialogPeers)) + |> `catch` { _ -> Signal in + return .single(Api.Bool.boolFalse) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + } + } + } + } + |> switchToLatest + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeRecentlyUsedMediaOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeRecentlyUsedMediaOperations.swift new file mode 100644 index 0000000000..ad6ddc68b5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeRecentlyUsedMediaOperations.swift @@ -0,0 +1,199 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeRecentlyUsedMediaOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeRecentlyUsedMediaOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeRecentlyUsedMediaOperations(postbox: Postbox, network: Network, category: RecentlyUsedMediaCategory, revalidationContext: MediaReferenceRevalidationContext) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag + switch category { + case .stickers: + tag = OperationLogTags.SynchronizeRecentlyUsedStickers + } + + let helper = Atomic(value: ManagedSynchronizeRecentlyUsedMediaOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation { + return synchronizeRecentlyUsedMedia(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private enum SaveRecentlyUsedMediaError { + case generic + case invalidReference +} + +private func synchronizeRecentlyUsedMedia(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeRecentlyUsedMediaOperation) -> Signal { + switch operation.content { + case let .add(id, accessHash, fileReference): + guard let fileReference = fileReference else { + return .complete() + } + + let addSticker: (Data) -> Signal = { fileReference in + return network.request(Api.functions.messages.saveRecentSticker(flags: 0, id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), unsave: .boolFalse)) + |> mapError { error -> SaveRecentlyUsedMediaError in + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + return .invalidReference + } + return .generic + } + } + + let initialSignal: Signal + if let reference = (fileReference.media.resource as? CloudDocumentMediaResource)?.fileReference { + initialSignal = addSticker(reference) + } else { + initialSignal = .fail(.invalidReference) + } + + return initialSignal + |> `catch` { error -> Signal in + switch error { + case .generic: + return .fail(.generic) + case .invalidReference: + return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + |> mapError { _ -> SaveRecentlyUsedMediaError in + return .generic + } + |> mapToSignal { validatedResource -> Signal in + if let resource = validatedResource.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = resource.fileReference { + return addSticker(reference) + } else { + return .fail(.generic) + } + } + } + } + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case let .remove(id, accessHash): + return network.request(Api.functions.messages.saveRecentSticker(flags: 0, id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer()), unsave: .boolTrue)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case .clear: + return network.request(Api.functions.messages.clearRecentStickers(flags: 0)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case .sync: + return managedRecentStickers(postbox: postbox, network: network) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedGifsOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedGifsOperations.swift new file mode 100644 index 0000000000..02d77d2686 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedGifsOperations.swift @@ -0,0 +1,187 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeSavedGifsOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeSavedGifsOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeSavedGifsOperations(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedGifs + + let helper = Atomic(value: ManagedSynchronizeSavedGifsOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeSavedGifsOperation { + return synchronizeSavedGifs(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private enum SaveGifError { + case generic + case invalidReference +} + +private func synchronizeSavedGifs(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedGifsOperation) -> Signal { + switch operation.content { + case let .add(id, accessHash, fileReference): + guard let fileReference = fileReference else { + return .complete() + } + + let saveGif: (Data) -> Signal = { fileReference in + return network.request(Api.functions.messages.saveGif(id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), unsave: .boolFalse)) + |> mapError { error -> SaveGifError in + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + return .invalidReference + } + return .generic + } + } + + let initialSignal: Signal + if let reference = (fileReference.media.resource as? CloudDocumentMediaResource)?.fileReference { + initialSignal = saveGif(reference) + } else { + initialSignal = .fail(.invalidReference) + } + + return initialSignal + |> `catch` { error -> Signal in + switch error { + case .generic: + return .fail(.generic) + case .invalidReference: + return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + |> mapError { _ -> SaveGifError in + return .generic + } + |> mapToSignal { validatedResource -> Signal in + if let resource = validatedResource.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = resource.fileReference { + return saveGif(reference) + } else { + return .fail(.generic) + } + } + } + } + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case let .remove(id, accessHash): + return network.request(Api.functions.messages.saveGif(id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer()), unsave: .boolTrue)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case .sync: + return managedRecentGifs(postbox: postbox, network: network) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedStickersOperations.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedStickersOperations.swift new file mode 100644 index 0000000000..e4c206538e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeSavedStickersOperations.swift @@ -0,0 +1,187 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private final class ManagedSynchronizeSavedStickersOperationsHelper { + var operationDisposables: [Int32: Disposable] = [:] + + func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) { + var disposeOperations: [Disposable] = [] + var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = [] + + var hasRunningOperationForPeerId = Set() + var validMergedIndices = Set() + for entry in entries { + if !hasRunningOperationForPeerId.contains(entry.peerId) { + hasRunningOperationForPeerId.insert(entry.peerId) + validMergedIndices.insert(entry.mergedIndex) + + if self.operationDisposables[entry.mergedIndex] == nil { + let disposable = MetaDisposable() + beginOperations.append((entry, disposable)) + self.operationDisposables[entry.mergedIndex] = disposable + } + } + } + + var removeMergedIndices: [Int32] = [] + for (mergedIndex, disposable) in self.operationDisposables { + if !validMergedIndices.contains(mergedIndex) { + removeMergedIndices.append(mergedIndex) + disposeOperations.append(disposable) + } + } + + for mergedIndex in removeMergedIndices { + self.operationDisposables.removeValue(forKey: mergedIndex) + } + + return (disposeOperations, beginOperations) + } + + func reset() -> [Disposable] { + let disposables = Array(self.operationDisposables.values) + self.operationDisposables.removeAll() + return disposables + } +} + +private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { + return postbox.transaction { transaction -> Signal in + var result: PeerMergedOperationLogEntry? + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in + if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeSavedStickersOperation { + result = entry.mergedEntry! + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } else { + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + + return f(transaction, result) + } |> switchToLatest +} + +func managedSynchronizeSavedStickersOperations(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { + return Signal { _ in + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedStickers + + let helper = Atomic(value: ManagedSynchronizeSavedStickersOperationsHelper()) + + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in + let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in + return helper.update(view.entries) + } + + for disposable in disposeOperations { + disposable.dispose() + } + + for (entry, disposable) in beginOperations { + let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + if let entry = entry { + if let operation = entry.contents as? SynchronizeSavedStickersOperation { + return synchronizeSavedStickers(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + } else { + assertionFailure() + } + } + return .complete() + }) + |> then(postbox.transaction { transaction -> Void in + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) + }) + + disposable.set(signal.start()) + } + }) + + return ActionDisposable { + let disposables = helper.with { helper -> [Disposable] in + return helper.reset() + } + for disposable in disposables { + disposable.dispose() + } + disposable.dispose() + } + } +} + +private enum SaveStickerError { + case generic + case invalidReference +} + +private func synchronizeSavedStickers(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedStickersOperation) -> Signal { + switch operation.content { + case let .add(id, accessHash, fileReference): + guard let fileReference = fileReference else { + return .complete() + } + + let saveSticker: (Data) -> Signal = { fileReference in + return network.request(Api.functions.messages.faveSticker(id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), unfave: .boolFalse)) + |> mapError { error -> SaveStickerError in + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + return .invalidReference + } + return .generic + } + } + + let initialSignal: Signal + if let reference = (fileReference.media.resource as? CloudDocumentMediaResource)?.fileReference { + initialSignal = saveSticker(reference) + } else { + initialSignal = .fail(.invalidReference) + } + + return initialSignal + |> `catch` { error -> Signal in + switch error { + case .generic: + return .fail(.generic) + case .invalidReference: + return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + |> mapError { _ -> SaveStickerError in + return .generic + } + |> mapToSignal { validatedResource -> Signal in + if let resource = validatedResource.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = resource.fileReference { + return saveSticker(reference) + } else { + return .fail(.generic) + } + } + } + } + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case let .remove(id, accessHash): + return network.request(Api.functions.messages.faveSticker(id: .inputDocument(id: id, accessHash: accessHash, fileReference: Buffer()), unfave: .boolTrue)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + case .sync: + return managedSavedStickers(postbox: postbox, network: network) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ManagedVoipConfigurationUpdates.swift b/submodules/TelegramCore/TelegramCore/ManagedVoipConfigurationUpdates.swift new file mode 100644 index 0000000000..b3be41ac0e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ManagedVoipConfigurationUpdates.swift @@ -0,0 +1,34 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +func managedVoipConfigurationUpdates(postbox: Postbox, network: Network) -> Signal { + let poll = Signal { subscriber in + return (network.request(Api.functions.phone.getCallConfig()) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + switch result { + case let .dataJSON(data): + updateVoipConfiguration(transaction: transaction, { configuration in + var configuration = configuration + configuration.serializedData = data + return configuration + }) + } + } + }).start() + } + return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} diff --git a/submodules/TelegramCore/TelegramCore/MarkAllChatsAsRead.swift b/submodules/TelegramCore/TelegramCore/MarkAllChatsAsRead.swift new file mode 100644 index 0000000000..c2d0d9ad1b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MarkAllChatsAsRead.swift @@ -0,0 +1,79 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func markAllChatsAsRead(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + return network.request(Api.functions.messages.getDialogUnreadMarks()) + |> map(Optional.init) + |> `catch` { _ -> Signal<[Api.DialogPeer]?, NoError> in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .complete() + } + + return postbox.transaction { transaction -> Signal in + var signals: [Signal] = [] + for peer in result { + switch peer { + case let .dialogPeer(peer): + let peerId = peer.peerId + if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) { + signals.append(network.request(Api.functions.channels.readHistory(channel: inputChannel, maxId: Int32.max - 1)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + }) + } + } else if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + if let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) { + signals.append(network.request(Api.functions.messages.readHistory(peer: inputPeer, maxId: Int32.max - 1)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } + return .complete() + }) + } + } else { + assertionFailure() + } + case .dialogPeerFolder: + assertionFailure() + } + } + + let applyLocally = postbox.transaction { transaction -> Void in + + } + + return combineLatest(signals) + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(applyLocally) + } |> switchToLatest + } +} diff --git a/submodules/TelegramCore/TelegramCore/MarkMessageContentAsConsumedInteractively.swift b/submodules/TelegramCore/TelegramCore/MarkMessageContentAsConsumedInteractively.swift new file mode 100644 index 0000000000..e878335882 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MarkMessageContentAsConsumedInteractively.swift @@ -0,0 +1,159 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func markMessageContentAsConsumedInteractively(postbox: Postbox, messageId: MessageId) -> Signal { + return postbox.transaction { transaction -> Void in + if let message = transaction.getMessage(messageId), message.flags.contains(.Incoming) { + var updateMessage = false + var updatedAttributes = message.attributes + + for i in 0 ..< updatedAttributes.count { + if let attribute = updatedAttributes[i] as? ConsumableContentMessageAttribute { + if !attribute.consumed { + updatedAttributes[i] = ConsumableContentMessageAttribute(consumed: true) + updateMessage = true + + if message.id.peerId.namespace == Namespaces.Peer.SecretChat { + if let state = transaction.getPeerChatState(message.id.peerId) as? SecretChatState { + var layer: SecretChatLayer? + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + if let layer = layer { + var globallyUniqueIds: [Int64] = [] + if let globallyUniqueId = message.globallyUniqueId { + globallyUniqueIds.append(globallyUniqueId) + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: message.id.peerId, operation: SecretChatOutgoingOperationContents.readMessagesContent(layer: layer, actionGloballyUniqueId: arc4random64(), globallyUniqueIds: globallyUniqueIds), state: state) + if updatedState != state { + transaction.setPeerChatState(message.id.peerId, state: updatedState) + } + } + } + } + } else { + addSynchronizeConsumeMessageContentsOperation(transaction: transaction, messageIds: [message.id]) + } + } + } else if let attribute = updatedAttributes[i] as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed { + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: messageId, action: ConsumePersonalMessageAction()) + updatedAttributes[i] = ConsumablePersonalMentionMessageAttribute(consumed: attribute.consumed, pending: true) + } + } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + for i in 0 ..< updatedAttributes.count { + if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute { + if attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0 { + updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp) + updateMessage = true + + transaction.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: messageId) + + if messageId.peerId.namespace == Namespaces.Peer.SecretChat { + var layer: SecretChatLayer? + let state = transaction.getPeerChatState(message.id.peerId) as? SecretChatState + if let state = state { + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + } + + if let state = state, let layer = layer, let globallyUniqueId = message.globallyUniqueId { + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: messageId.peerId, operation: .readMessagesContent(layer: layer, actionGloballyUniqueId: arc4random64(), globallyUniqueIds: [globallyUniqueId]), state: state) + if updatedState != state { + transaction.setPeerChatState(messageId.peerId, state: updatedState) + } + } + } + } + break + } + } + + if updateMessage { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + } + } + } +} + +func markMessageContentAsConsumedRemotely(transaction: Transaction, messageId: MessageId) { + if let message = transaction.getMessage(messageId) { + var updateMessage = false + var updatedAttributes = message.attributes + var updatedMedia = message.media + var updatedTags = message.tags + + for i in 0 ..< updatedAttributes.count { + if let attribute = updatedAttributes[i] as? ConsumableContentMessageAttribute { + if !attribute.consumed { + updatedAttributes[i] = ConsumableContentMessageAttribute(consumed: true) + updateMessage = true + } + } else if let attribute = updatedAttributes[i] as? ConsumablePersonalMentionMessageAttribute, !attribute.consumed { + if attribute.pending { + transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: messageId, action: nil) + } + updatedAttributes[i] = ConsumablePersonalMentionMessageAttribute(consumed: true, pending: false) + updatedTags.remove(.unseenPersonalMessage) + updateMessage = true + } + } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + for i in 0 ..< updatedAttributes.count { + if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute { + if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia { + updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp) + updateMessage = true + + if message.id.peerId.namespace == Namespaces.Peer.SecretChat { + transaction.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: messageId) + } else { + for i in 0 ..< updatedMedia.count { + if let _ = updatedMedia[i] as? TelegramMediaImage { + updatedMedia[i] = TelegramMediaExpiredContent(data: .image) + } else if let _ = updatedMedia[i] as? TelegramMediaFile { + updatedMedia[i] = TelegramMediaExpiredContent(data: .file) + } + } + } + } + break + } + } + + if updateMessage { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia)) + }) + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/MediaResourceApiUtils.swift b/submodules/TelegramCore/TelegramCore/MediaResourceApiUtils.swift new file mode 100644 index 0000000000..d3471fd83c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MediaResourceApiUtils.swift @@ -0,0 +1,7 @@ +import Foundation + +extension SecretChatFileReference { + func resource(key: SecretFileEncryptionKey, decryptedSize: Int32) -> SecretFileMediaResource { + return SecretFileMediaResource(fileId: self.id, accessHash: self.accessHash, containerSize: self.size, decryptedSize: decryptedSize, datacenterId: Int(self.datacenterId), key: key) + } +} diff --git a/submodules/TelegramCore/TelegramCore/MediaResourceNetworkStatsTag.swift b/submodules/TelegramCore/TelegramCore/MediaResourceNetworkStatsTag.swift new file mode 100644 index 0000000000..0dd31adc82 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MediaResourceNetworkStatsTag.swift @@ -0,0 +1,22 @@ +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum MediaResourceStatsCategory { + case generic + case image + case video + case audio + case file + case call +} + +public final class TelegramMediaResourceFetchTag: MediaResourceFetchTag { + public let statsCategory: MediaResourceStatsCategory + + public init(statsCategory: MediaResourceStatsCategory) { + self.statsCategory = statsCategory + } +} diff --git a/submodules/TelegramCore/TelegramCore/MemoryBufferExtensions.swift b/submodules/TelegramCore/TelegramCore/MemoryBufferExtensions.swift new file mode 100644 index 0000000000..6dc8dbc7c9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MemoryBufferExtensions.swift @@ -0,0 +1,26 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public extension MemoryBuffer { + public convenience init(_ buffer: Buffer) { + let memory = malloc(Int(buffer.size))! + memcpy(memory, buffer.data, Int(buffer.size)) + self.init(memory: memory, capacity: Int(buffer.size), length: Int(buffer.size), freeWhenDone: true) + } +} + +extension Buffer { + convenience init(bufferNoCopy: MemoryBuffer) { + self.init(memory: bufferNoCopy.memory, size: bufferNoCopy.length, capacity: bufferNoCopy.length, freeWhenDone: false) + } + + convenience init(buffer: MemoryBuffer) { + let memory = malloc(buffer.length)! + memcpy(memory, buffer.memory, buffer.length) + self.init(memory: memory, size: buffer.length, capacity: buffer.length, freeWhenDone: true) + } +} diff --git a/submodules/TelegramCore/TelegramCore/MessageMediaPreuploadManager.swift b/submodules/TelegramCore/TelegramCore/MessageMediaPreuploadManager.swift new file mode 100644 index 0000000000..5b34f66a6f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MessageMediaPreuploadManager.swift @@ -0,0 +1,134 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private func localIdForResource(_ resource: MediaResource) -> Int64? { + if let resource = resource as? LocalFileMediaResource { + return resource.fileId + } + return nil +} + +private final class MessageMediaPreuploadManagerUploadContext { + let disposable = MetaDisposable() + var progress: Float? + var result: MultipartUploadResult? + let subscribers = Bag<(MultipartUploadResult) -> Void>() + + deinit { + self.disposable.dispose() + } +} + +private final class MessageMediaPreuploadManagerContext { + private let queue: Queue + + private var uploadContexts: [Int64: MessageMediaPreuploadManagerUploadContext] = [:] + + init(queue: Queue) { + self.queue = queue + + assert(self.queue.isCurrent()) + } + + func add(network: Network, postbox: Postbox, id: Int64, encrypt: Bool, tag: MediaResourceFetchTag?, source: Signal) { + let context = MessageMediaPreuploadManagerUploadContext() + self.uploadContexts[id] = context + let queue = self.queue + context.disposable.set(multipartUpload(network: network, postbox: postbox, source: .custom(source), encrypt: encrypt, tag: tag, hintFileSize: nil, hintFileIsLarge: false).start(next: { [weak self] next in + queue.async { + if let strongSelf = self, let context = strongSelf.uploadContexts[id] { + switch next { + case let .progress(value): + print("progress") + context.progress = value + default: + print("result") + context.result = next + } + for subscriber in context.subscribers.copyItems() { + subscriber(next) + } + } + } + })) + } + + func upload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool) -> Signal { + let queue = self.queue + return Signal { [weak self] subscriber in + if let strongSelf = self { + if case let .resource(resource) = source, let id = localIdForResource(resource.resource), let context = strongSelf.uploadContexts[id] { + if let result = context.result { + subscriber.putNext(.progress(1.0)) + subscriber.putNext(result) + subscriber.putCompletion() + return EmptyDisposable + } else if let progress = context.progress { + subscriber.putNext(.progress(progress)) + } + let index = context.subscribers.add({ next in + subscriber.putNext(next) + switch next { + case .inputFile, .inputSecretFile: + subscriber.putCompletion() + case .progress: + break + } + }) + return ActionDisposable { + queue.async { + if let strongSelf = self, let context = strongSelf.uploadContexts[id] { + context.subscribers.remove(index) + } + } + } + } else { + return multipartUpload(network: network, postbox: postbox, source: source, encrypt: encrypt, tag: tag, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge).start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } + } else { + subscriber.putError(.generic) + return EmptyDisposable + } + } |> runOn(self.queue) + } +} + +public final class MessageMediaPreuploadManager { + private let impl: QueueLocalObject + + init() { + let queue = Queue() + self.impl = QueueLocalObject(queue: queue, generate: { + return MessageMediaPreuploadManagerContext(queue: queue) + }) + } + + public func add(network: Network, postbox: Postbox, id: Int64, encrypt: Bool, tag: MediaResourceFetchTag?, source: Signal) { + self.impl.with { context in + context.add(network: network, postbox: postbox, id: id, encrypt: encrypt, tag: tag, source: source) + } + } + + func upload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool) -> Signal { + return Signal, MultipartUploadError> { subscriber in + self.impl.with { context in + subscriber.putNext(context.upload(network: network, postbox: postbox, source: source, encrypt: encrypt, tag: tag, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge)) + subscriber.putCompletion() + } + return EmptyDisposable + } + |> switchToLatest + } +} diff --git a/submodules/TelegramCore/TelegramCore/MessageUtils.swift b/submodules/TelegramCore/TelegramCore/MessageUtils.swift new file mode 100644 index 0000000000..d5dcdb7cec --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MessageUtils.swift @@ -0,0 +1,168 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public extension MessageFlags { + public var isSending: Bool { + return (self.contains(.Unsent) || self.contains(.Sending)) && !self.contains(.Failed) + } +} + +public extension Message { + var visibleButtonKeyboardMarkup: ReplyMarkupMessageAttribute? { + for attribute in self.attributes { + if let attribute = attribute as? ReplyMarkupMessageAttribute { + if !attribute.flags.contains(.inline) && !attribute.rows.isEmpty { + if attribute.flags.contains(.personal) { + if !personal { + return nil + } + } + return attribute + } + } + } + return nil + } + + public var muted: Bool { + for attribute in self.attributes { + if let attribute = attribute as? NotificationInfoMessageAttribute { + return attribute.flags.contains(.muted) + } + } + return false + } + + public var personal: Bool { + for attribute in self.attributes { + if let attribute = attribute as? NotificationInfoMessageAttribute { + return attribute.flags.contains(.personal) + } + } + return false + } + + var requestsSetupReply: Bool { + for attribute in self.attributes { + if let attribute = attribute as? ReplyMarkupMessageAttribute { + if !attribute.flags.contains(.inline) { + if attribute.flags.contains(.personal) { + if !personal { + return false + } + } + return attribute.flags.contains(.setupReply) + } + } + } + return false + } + + var isScam: Bool { + if let author = self.author, author.isScam { + return true + } + if let forwardAuthor = self.forwardInfo?.author, forwardAuthor.isScam { + return true + } + for attribute in self.attributes { + if let attribute = attribute as? InlineBotMessageAttribute, let peerId = attribute.peerId, let bot = self.peers[peerId] as? TelegramUser, bot.isScam { + return true + } + } + return false + } + + public var sourceReference: SourceReferenceMessageAttribute? { + for attribute in self.attributes { + if let attribute = attribute as? SourceReferenceMessageAttribute { + return attribute + } + } + return nil + } + + public var effectiveAuthor: Peer? { + if let forwardInfo = self.forwardInfo, let sourceReference = self.sourceReference, forwardInfo.author?.id == sourceReference.messageId.peerId { + if let peer = self.peers[sourceReference.messageId.peerId] { + return peer + } + } + return self.author + } +} + +func messagesIdsGroupedByPeerId(_ ids: Set) -> [PeerId: [MessageId]] { + var dict: [PeerId: [MessageId]] = [:] + + for id in ids { + let peerId = id.peerId + if dict[peerId] == nil { + dict[peerId] = [id] + } else { + dict[peerId]!.append(id) + } + } + + return dict +} + +func messagesIdsGroupedByPeerId(_ ids: [MessageId]) -> [PeerId: [MessageId]] { + var dict: [PeerId: [MessageId]] = [:] + + for id in ids { + let peerId = id.peerId + if dict[peerId] == nil { + dict[peerId] = [id] + } else { + dict[peerId]!.append(id) + } + } + + return dict +} + +func locallyRenderedMessage(message: StoreMessage, peers: [PeerId: Peer]) -> Message? { + guard case let .Id(id) = message.id else { + return nil + } + + var messagePeers = SimpleDictionary() + + var author: Peer? + if let authorId = message.authorId { + author = peers[authorId] + if let author = author { + messagePeers[author.id] = author + } + } + + if let peer = peers[id.peerId] { + messagePeers[peer.id] = peer + } + + for media in message.media { + for peerId in media.peerIds { + if let peer = peers[peerId] { + messagePeers[peer.id] = peer + } + } + } + + var forwardInfo: MessageForwardInfo? + if let info = message.forwardInfo { + forwardInfo = MessageForwardInfo(author: info.authorId.flatMap({ peers[$0] }), source: info.sourceId.flatMap({ peers[$0] }), sourceMessageId: info.sourceMessageId, date: info.date, authorSignature: info.authorSignature) + if let author = forwardInfo?.author { + messagePeers[author.id] = author + } + if let source = forwardInfo?.source { + messagePeers[source.id] = source + } + } + + return Message(stableId: 0, stableVersion: 0, id: id, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: message.timestamp, flags: MessageFlags(message.flags), tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: forwardInfo, author: author, text: message.text, attributes: message.attributes, media: message.media, peers: messagePeers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) +} diff --git a/submodules/TelegramCore/TelegramCore/MonotonicTime.h b/submodules/TelegramCore/TelegramCore/MonotonicTime.h new file mode 100644 index 0000000000..a6fff4b31b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MonotonicTime.h @@ -0,0 +1,4 @@ +#import + +int64_t MonotonicGetBootTimestamp(); +int64_t MonotonicGetUptime(); diff --git a/submodules/TelegramCore/TelegramCore/MonotonicTime.m b/submodules/TelegramCore/TelegramCore/MonotonicTime.m new file mode 100644 index 0000000000..0bdac21a5a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MonotonicTime.m @@ -0,0 +1,29 @@ +#import "MonotonicTime.h" + +#include + +int64_t MonotonicGetBootTimestamp() { + struct timeval boottime; + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); + if (rc != 0) { + return 0; + } + return boottime.tv_sec * 1000000 + boottime.tv_usec; +} + +int64_t MonotonicGetUptime() { + int64_t before_now; + int64_t after_now; + struct timeval now; + + after_now = MonotonicGetBootTimestamp(); + do { + before_now = after_now; + gettimeofday(&now, NULL); + after_now = MonotonicGetBootTimestamp(); + } while (after_now != before_now); + + return now.tv_sec * 1000000 + now.tv_usec - before_now; +} diff --git a/submodules/TelegramCore/TelegramCore/MonotonicTime.swift b/submodules/TelegramCore/TelegramCore/MonotonicTime.swift new file mode 100644 index 0000000000..c2aefc6d6e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MonotonicTime.swift @@ -0,0 +1,13 @@ +import Foundation + +import TelegramCorePrivateModule + +public struct MonotonicTime { + public func getBootTimestamp() -> Int64 { + return MonotonicGetBootTimestamp() + } + + public func getUptime() -> Int64 { + return MonotonicGetUptime() + } +} diff --git a/submodules/TelegramCore/TelegramCore/MultipartFetch.swift b/submodules/TelegramCore/TelegramCore/MultipartFetch.swift new file mode 100644 index 0000000000..87ce3294b6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MultipartFetch.swift @@ -0,0 +1,762 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +#if os(macOS) + private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else + private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private final class MultipartDownloadState { + let aesKey: Data + var aesIv: Data + let decryptedSize: Int32? + + var currentSize: Int32 = 0 + + init(encryptionKey: SecretFileEncryptionKey?, decryptedSize: Int32?) { + if let encryptionKey = encryptionKey { + self.aesKey = encryptionKey.aesKey + self.aesIv = encryptionKey.aesIv + } else { + self.aesKey = Data() + self.aesIv = Data() + } + self.decryptedSize = decryptedSize + } + + func transform(offset: Int, data: Data) -> Data { + if self.aesKey.count != 0 { + var decryptedData = data + assert(decryptedSize != nil) + assert(decryptedData.count % 16 == 0) + let decryptedDataCount = decryptedData.count + assert(offset == Int(self.currentSize)) + decryptedData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + self.aesIv.withUnsafeMutableBytes { (iv: UnsafeMutablePointer) -> Void in + MTAesDecryptBytesInplaceAndModifyIv(bytes, decryptedDataCount, self.aesKey, iv) + } + } + if self.currentSize + Int32(decryptedData.count) > self.decryptedSize! { + decryptedData.count = Int(self.decryptedSize! - self.currentSize) + } + self.currentSize += Int32(decryptedData.count) + return decryptedData + } else { + return data + } + } +} + +private enum MultipartFetchDownloadError { + case generic + case switchToCdn(id: Int32, token: Data, key: Data, iv: Data, partHashes: [Int32: Data]) + case reuploadToCdn(masterDatacenterId: Int32, token: Data) + case revalidateMediaReference + case hashesMissing +} + +private enum MultipartFetchGenericLocationResult { + case none + case location(Api.InputFileLocation) + case revalidate +} + +private enum MultipartFetchMasterLocation { + case generic(Int32, (TelegramMediaResource, MediaResourceReference?, Data?) -> MultipartFetchGenericLocationResult) + case web(Int32, Api.InputWebFileLocation) + + var datacenterId: Int32 { + switch self { + case let .generic(id, _): + return id + case let .web(id, _): + return id + } + } +} + +private struct DownloadWrapper { + let consumerId: Int64 + let datacenterId: Int32 + let isCdn: Bool + let network: Network + + func request(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse), tag: MediaResourceFetchTag?, continueInBackground: Bool) -> Signal { + let target: MultiplexedRequestTarget + if self.isCdn { + target = .cdn(Int(self.datacenterId)) + } else { + target = .main(Int(self.datacenterId)) + } + return network.multiplexedRequestManager.request(to: target, consumerId: self.consumerId, data: data, tag: tag, continueInBackground: continueInBackground) + } +} + +private func roundUp(_ value: Int, to multiple: Int) -> Int { + if multiple == 0 { + return value + } + + let remainder = value % multiple + if remainder == 0 { + return value + } + + return value + multiple - remainder +} + +private let dataHashLength: Int32 = 128 * 1024 + +private final class MultipartCdnHashSource { + private let queue: Queue + + private let fileToken: Data + private let masterDownload: DownloadWrapper + private let continueInBackground: Bool + + private var knownUpperBound: Int32 + private var hashes: [Int32: Data] = [:] + private var requestOffsetAndDisposable: (Int32, Disposable)? + private var requestedUpperBound: Int32? + + private var subscribers = Bag<(Int32, Int32, ([Int32: Data]) -> Void)>() + + init(queue: Queue, fileToken: Data, hashes: [Int32: Data], masterDownload: DownloadWrapper, continueInBackground: Bool) { + assert(queue.isCurrent()) + + self.queue = queue + self.fileToken = fileToken + self.masterDownload = masterDownload + self.continueInBackground = continueInBackground + + let knownUpperBound: Int32 = 0 + /*self.hashes = hashes + for (offset, _) in hashes { + assert(offset % dataHashLength == 0) + knownUpperBound = max(knownUpperBound, offset + dataHashLength) + }*/ + self.knownUpperBound = knownUpperBound + } + + deinit { + assert(self.queue.isCurrent()) + + self.requestOffsetAndDisposable?.1.dispose() + } + + private func take(offset: Int32, limit: Int32) -> [Int32: Data]? { + assert(offset % dataHashLength == 0) + assert(limit % dataHashLength == 0) + + var result: [Int32: Data] = [:] + + var localOffset: Int32 = 0 + while localOffset < limit { + if let hash = self.hashes[offset + localOffset] { + result[offset + localOffset] = hash + } else { + return nil + } + localOffset += dataHashLength + } + + return result + } + + func get(offset: Int32, limit: Int32) -> Signal<[Int32: Data], MultipartFetchDownloadError> { + assert(self.queue.isCurrent()) + + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + + queue.async { + if let strongSelf = self { + if let result = strongSelf.take(offset: offset, limit: limit) { + subscriber.putNext(result) + subscriber.putCompletion() + } else { + let index = strongSelf.subscribers.add((offset, limit, { result in + subscriber.putNext(result) + subscriber.putCompletion() + })) + + disposable.set(ActionDisposable { + queue.async { + if let strongSelf = self { + strongSelf.subscribers.remove(index) + } + } + }) + + if let requestedUpperBound = strongSelf.requestedUpperBound { + strongSelf.requestedUpperBound = max(requestedUpperBound, offset + limit) + } else { + strongSelf.requestedUpperBound = offset + limit + } + + if strongSelf.requestOffsetAndDisposable == nil { + strongSelf.requestMore() + } else { + if let requestedUpperBound = strongSelf.requestedUpperBound { + strongSelf.requestedUpperBound = max(requestedUpperBound, offset + limit) + } else { + strongSelf.requestedUpperBound = offset + limit + } + } + } + } + } + + return disposable + } + } + + private func requestMore() { + assert(self.queue.isCurrent()) + + let requestOffset = self.knownUpperBound + let disposable = MetaDisposable() + self.requestOffsetAndDisposable = (requestOffset, disposable) + let queue = self.queue + let fileToken = self.fileToken + disposable.set((self.masterDownload.request(Api.functions.upload.getCdnFileHashes(fileToken: Buffer(data: fileToken), offset: requestOffset), tag: nil, continueInBackground: self.continueInBackground) + |> map { partHashes -> [Int32: Data] in + var parsedPartHashes: [Int32: Data] = [:] + for part in partHashes { + switch part { + case let .fileHash(offset, limit, bytes): + assert(limit == 128 * 1024) + parsedPartHashes[offset] = bytes.makeData() + } + } + return parsedPartHashes + } + |> `catch` { _ -> Signal<[Int32: Data], NoError> in + return .single([:]) + } |> deliverOn(queue)).start(next: { [weak self] result in + if let strongSelf = self { + if strongSelf.requestOffsetAndDisposable?.0 == requestOffset { + strongSelf.requestOffsetAndDisposable = nil + + for (hashOffset, hashData) in result { + assert(hashOffset % dataHashLength == 0) + strongSelf.knownUpperBound = max(strongSelf.knownUpperBound, hashOffset + dataHashLength) + strongSelf.hashes[hashOffset] = hashData + } + + for (index, item) in strongSelf.subscribers.copyItemsWithIndices() { + let (offset, limit, subscriber) = item + if let data = strongSelf.take(offset: offset, limit: limit) { + strongSelf.subscribers.remove(index) + subscriber(data) + } + } + + if let requestedUpperBound = strongSelf.requestedUpperBound, requestedUpperBound > strongSelf.knownUpperBound { + strongSelf.requestMore() + } + } else { + //assertionFailure() + } + } + })) + } +} + +private enum MultipartFetchSource { + case none + case master(location: MultipartFetchMasterLocation, download: DownloadWrapper) + case cdn(masterDatacenterId: Int32, fileToken: Data, key: Data, iv: Data, download: DownloadWrapper, masterDownload: DownloadWrapper, hashSource: MultipartCdnHashSource) + + func request(offset: Int32, limit: Int32, tag: MediaResourceFetchTag?, resource: TelegramMediaResource, resourceReference: MediaResourceReference?, fileReference: Data?, continueInBackground: Bool) -> Signal { + switch self { + case .none: + return .never() + case let .master(location, download): + var updatedLength = roundUp(Int(limit), to: 4096) + while updatedLength % 4096 != 0 || 1048576 % updatedLength != 0 { + updatedLength += 1 + } + + switch location { + case let .generic(_, location): + switch location(resource, resourceReference, fileReference) { + case .none: + return .fail(.revalidateMediaReference) + case .revalidate: + return .fail(.revalidateMediaReference) + case let .location(parsedLocation): + return download.request(Api.functions.upload.getFile(location: parsedLocation, offset: offset, limit: Int32(updatedLength)), tag: tag, continueInBackground: continueInBackground) + |> mapError { error -> MultipartFetchDownloadError in + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + return .revalidateMediaReference + } + return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .file(_, _, bytes): + var resultData = bytes.makeData() + if resultData.count > Int(limit) { + resultData.count = Int(limit) + } + return .single(resultData) + case let .fileCdnRedirect(dcId, fileToken, encryptionKey, encryptionIv, partHashes): + var parsedPartHashes: [Int32: Data] = [:] + for part in partHashes { + switch part { + case let .fileHash(offset, limit, bytes): + assert(limit == 128 * 1024) + parsedPartHashes[offset] = bytes.makeData() + } + } + return .fail(.switchToCdn(id: dcId, token: fileToken.makeData(), key: encryptionKey.makeData(), iv: encryptionIv.makeData(), partHashes: parsedPartHashes)) + } + } + } + case let .web(_, location): + return download.request(Api.functions.upload.getWebFile(location: location, offset: offset, limit: Int32(updatedLength)), tag: tag, continueInBackground: continueInBackground) + |> mapError { error -> MultipartFetchDownloadError in + return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .webFile(_, _, _, _, bytes): + var resultData = bytes.makeData() + if resultData.count > Int(limit) { + resultData.count = Int(limit) + } + return .single(resultData) + } + } + } + case let .cdn(masterDatacenterId, fileToken, key, iv, download, _, hashSource): + var updatedLength = roundUp(Int(limit), to: 4096) + while updatedLength % 4096 != 0 || 1048576 % updatedLength != 0 { + updatedLength += 1 + } + + let part = download.request(Api.functions.upload.getCdnFile(fileToken: Buffer(data: fileToken), offset: offset, limit: Int32(updatedLength)), tag: nil, continueInBackground: continueInBackground) + |> mapError { _ -> MultipartFetchDownloadError in + return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .cdnFileReuploadNeeded(token): + return .fail(.reuploadToCdn(masterDatacenterId: masterDatacenterId, token: token.makeData())) + case let .cdnFile(bytes): + if bytes.size == 0 { + return .single(bytes.makeData()) + } else { + var partIv = iv + let partIvCount = partIv.count + partIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + var ivOffset: Int32 = (offset / 16).bigEndian + memcpy(bytes.advanced(by: partIvCount - 4), &ivOffset, 4) + } + return .single(MTAesCtrDecrypt(bytes.makeData(), key, partIv)) + } + } + } + + return combineLatest(part, hashSource.get(offset: offset, limit: limit)) + |> mapToSignal { partData, hashData -> Signal in + var localOffset = 0 + while localOffset < partData.count { + let dataToHash = partData.subdata(in: localOffset ..< min(partData.count, localOffset + Int(dataHashLength))) + if let hash = hashData[offset + Int32(localOffset)] { + let localHash = MTSha256(dataToHash) + if localHash != hash { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + + localOffset += Int(dataHashLength) + } + return .single(partData) + } + } + } +} + +private final class MultipartFetchManager { + let parallelParts: Int + let defaultPartSize = 128 * 1024 + let partAlignment = 128 * 1024 + + var resource: TelegramMediaResource + var resourceReference: MediaResourceReference? + var fileReference: Data? + let parameters: MediaResourceFetchParameters? + let consumerId: Int64 + + let queue = Queue() + + var currentIntervals: [(Range, MediaBoxFetchPriority)]? + var currentFilledRanges = IndexSet() + + var completeSize: Int? + var completeSizeReported = false + + let postbox: Postbox + let network: Network + let revalidationContext: MediaReferenceRevalidationContext + let continueInBackground: Bool + let partReady: (Int, Data) -> Void + let reportCompleteSize: (Int) -> Void + + private var source: MultipartFetchSource + + var fetchingParts: [Int: (Int, Disposable)] = [:] + var nextFetchingPartId = 0 + var fetchedParts: [Int: (Int, Data)] = [:] + var cachedPartHashes: [Int: Data] = [:] + + var reuploadingToCdn = false + let reuploadToCdnDisposable = MetaDisposable() + + var revalidatedMediaReference = false + var revalidatingMediaReference = false + let revalidateMediaReferenceDisposable = MetaDisposable() + + var state: MultipartDownloadState + + var rangesDisposable: Disposable? + + init(resource: TelegramMediaResource, parameters: MediaResourceFetchParameters?, size: Int?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, encryptionKey: SecretFileEncryptionKey?, decryptedSize: Int32?, location: MultipartFetchMasterLocation, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, partReady: @escaping (Int, Data) -> Void, reportCompleteSize: @escaping (Int) -> Void) { + self.resource = resource + self.parameters = parameters + self.consumerId = arc4random64() + + self.completeSize = size + if let _ = size { + self.parallelParts = 4 + } else { + self.parallelParts = 1 + } + + if let info = parameters?.info as? TelegramCloudMediaResourceFetchInfo { + self.fileReference = info.reference.apiFileReference + self.continueInBackground = info.continueInBackground + self.resourceReference = info.reference + } else { + self.continueInBackground = false + self.resourceReference = nil + } + + self.state = MultipartDownloadState(encryptionKey: encryptionKey, decryptedSize: decryptedSize) + self.postbox = postbox + self.network = network + self.revalidationContext = revalidationContext + self.source = .master(location: location, download: DownloadWrapper(consumerId: self.consumerId, datacenterId: location.datacenterId, isCdn: false, network: network)) + self.partReady = partReady + self.reportCompleteSize = reportCompleteSize + + self.rangesDisposable = (intervals + |> deliverOn(self.queue)).start(next: { [weak self] intervals in + if let strongSelf = self { + if let _ = strongSelf.currentIntervals { + strongSelf.currentIntervals = intervals + strongSelf.checkState() + } else { + strongSelf.currentIntervals = intervals + strongSelf.checkState() + } + } + }) + } + + deinit { + let rangesDisposable = self.rangesDisposable + self.queue.async { + rangesDisposable?.dispose() + } + } + + func start() { + self.queue.async { + self.checkState() + } + } + + func cancel() { + self.queue.async { + self.source = .none + for (_, (_, disposable)) in self.fetchingParts { + disposable.dispose() + } + self.reuploadToCdnDisposable.dispose() + self.revalidateMediaReferenceDisposable.dispose() + } + } + + func checkState() { + guard let currentIntervals = self.currentIntervals else { + return + } + + var removeFromFetchIntervals = self.currentFilledRanges + + let isSingleContiguousRange = currentIntervals.count == 1 + for offset in self.fetchedParts.keys.sorted() { + if let (_, data) = self.fetchedParts[offset] { + let partRange = offset ..< (offset + data.count) + removeFromFetchIntervals.insert(integersIn: partRange) + + var hasEarlierFetchingPart = false + if isSingleContiguousRange { + inner: for key in self.fetchingParts.keys { + if key < offset { + hasEarlierFetchingPart = true + break inner + } + } + } + + if !hasEarlierFetchingPart { + self.currentFilledRanges.insert(integersIn: partRange) + self.fetchedParts.removeValue(forKey: offset) + self.partReady(offset, self.state.transform(offset: offset, data: data)) + } + } + } + + for (offset, (size, _)) in self.fetchingParts { + removeFromFetchIntervals.insert(integersIn: offset ..< (offset + size)) + } + + if let completeSize = self.completeSize { + self.currentFilledRanges.insert(integersIn: completeSize ..< Int.max) + removeFromFetchIntervals.insert(integersIn: completeSize ..< Int.max) + } + + var intervalsToFetch: [(Range, MediaBoxFetchPriority)] = [] + for (interval, priority) in currentIntervals { + var intervalIndexSet = IndexSet(integersIn: interval) + intervalIndexSet.subtract(removeFromFetchIntervals) + for cleanInterval in intervalIndexSet.rangeView { + assert(!cleanInterval.isEmpty) + intervalsToFetch.append((cleanInterval, priority)) + } + } + + if let completeSize = self.completeSize { + if intervalsToFetch.isEmpty && self.fetchingParts.isEmpty && !self.completeSizeReported { + self.completeSizeReported = true + assert(self.fetchedParts.isEmpty) + if let decryptedSize = self.state.decryptedSize { + self.reportCompleteSize(Int(decryptedSize)) + } else { + self.reportCompleteSize(completeSize) + } + } + } + + while !intervalsToFetch.isEmpty && self.fetchingParts.count < self.parallelParts && !self.reuploadingToCdn && !self.revalidatingMediaReference { + var elevatedIndices: [Int] = [] + for i in 0 ..< intervalsToFetch.count { + if case .elevated = intervalsToFetch[i].1 { + elevatedIndices.append(i) + } + } + + let currentIntervalIndex: Int + if !elevatedIndices.isEmpty { + currentIntervalIndex = elevatedIndices[self.nextFetchingPartId % elevatedIndices.count] + } else { + currentIntervalIndex = self.nextFetchingPartId % intervalsToFetch.count + } + self.nextFetchingPartId += 1 + let (firstInterval, priority) = intervalsToFetch[currentIntervalIndex] + var downloadRange: Range = firstInterval.lowerBound ..< min(firstInterval.lowerBound + self.defaultPartSize, firstInterval.upperBound) + let rawRange: Range = downloadRange + if downloadRange.lowerBound % self.partAlignment != 0 { + let previousBoundary = (downloadRange.lowerBound / self.partAlignment) * self.partAlignment + downloadRange = previousBoundary ..< downloadRange.upperBound + } + if downloadRange.lowerBound / (1024 * 1024) != (downloadRange.upperBound - 1) / (1024 * 1024) { + let nextBoundary = (downloadRange.lowerBound / (1024 * 1024) + 1) * (1024 * 1024) + downloadRange = downloadRange.lowerBound ..< nextBoundary + } + + var intervalIndexSet = IndexSet(integersIn: intervalsToFetch[currentIntervalIndex].0) + intervalIndexSet.remove(integersIn: downloadRange) + intervalsToFetch.remove(at: currentIntervalIndex) + var insertIndex = currentIntervalIndex + for interval in intervalIndexSet.rangeView { + intervalsToFetch.insert((interval, priority), at: insertIndex) + insertIndex += 1 + } + var requestLimit = downloadRange.count + if requestLimit % self.partAlignment != 0 { + requestLimit = (requestLimit / self.partAlignment + 1) * self.partAlignment + } + + let part = self.source.request(offset: Int32(downloadRange.lowerBound), limit: Int32(requestLimit), tag: self.parameters?.tag, resource: self.resource, resourceReference: self.resourceReference, fileReference: self.fileReference, continueInBackground: self.continueInBackground) + |> deliverOn(self.queue) + let partDisposable = MetaDisposable() + self.fetchingParts[downloadRange.lowerBound] = (downloadRange.count, partDisposable) + + partDisposable.set(part.start(next: { [weak self] data in + guard let strongSelf = self else { + return + } + var data = data + if data.count < downloadRange.count { + strongSelf.completeSize = downloadRange.lowerBound + data.count + } + let _ = strongSelf.fetchingParts.removeValue(forKey: downloadRange.lowerBound) + strongSelf.fetchedParts[downloadRange.lowerBound] = (rawRange.lowerBound, data) + strongSelf.checkState() + }, error: { [weak self] error in + guard let strongSelf = self else { + return + } + let _ = strongSelf.fetchingParts.removeValue(forKey: downloadRange.lowerBound) + switch error { + case .generic: + break + case .revalidateMediaReference: + if !strongSelf.revalidatingMediaReference && !strongSelf.revalidatedMediaReference { + strongSelf.revalidatingMediaReference = true + if let info = strongSelf.parameters?.info as? TelegramCloudMediaResourceFetchInfo { + strongSelf.revalidateMediaReferenceDisposable.set((revalidateMediaResourceReference(postbox: strongSelf.postbox, network: strongSelf.network, revalidationContext: strongSelf.revalidationContext, info: info, resource: strongSelf.resource) + |> deliverOn(strongSelf.queue)).start(next: { validationResult in + if let strongSelf = self { + strongSelf.revalidatingMediaReference = false + strongSelf.revalidatedMediaReference = true + if let validatedResource = validationResult.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = validatedResource.fileReference { + strongSelf.fileReference = reference + } + strongSelf.resource = validationResult.updatedResource + strongSelf.resourceReference = validationResult.updatedReference + strongSelf.checkState() + } + }, error: { _ in + })) + } else { + Logger.shared.log("MultipartFetch", "reference invalidation requested, but no valid reference given") + } + } + case let .switchToCdn(id, token, key, iv, partHashes): + switch strongSelf.source { + case let .master(location, download): + strongSelf.source = .cdn(masterDatacenterId: location.datacenterId, fileToken: token, key: key, iv: iv, download: DownloadWrapper(consumerId: strongSelf.consumerId, datacenterId: id, isCdn: true, network: strongSelf.network), masterDownload: download, hashSource: MultipartCdnHashSource(queue: strongSelf.queue, fileToken: token, hashes: partHashes, masterDownload: download, continueInBackground: strongSelf.continueInBackground)) + strongSelf.checkState() + case .cdn, .none: + break + } + case let .reuploadToCdn(_, token): + switch strongSelf.source { + case .master, .none: + break + case let .cdn(_, fileToken, _, _, _, masterDownload, _): + if !strongSelf.reuploadingToCdn { + strongSelf.reuploadingToCdn = true + let reupload: Signal<[Api.FileHash], NoError> = masterDownload.request(Api.functions.upload.reuploadCdnFile(fileToken: Buffer(data: fileToken), requestToken: Buffer(data: token)), tag: nil, continueInBackground: strongSelf.continueInBackground) + |> `catch` { _ -> Signal<[Api.FileHash], NoError> in + return .single([]) + } + strongSelf.reuploadToCdnDisposable.set((reupload |> deliverOn(strongSelf.queue)).start(next: { _ in + if let strongSelf = self { + strongSelf.reuploadingToCdn = false + strongSelf.checkState() + } + })) + } + } + case .hashesMissing: + break + } + })) + } + } +} + +func multipartFetch(postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, resource: TelegramMediaResource, datacenterId: Int, size: Int?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?, encryptionKey: SecretFileEncryptionKey? = nil, decryptedSize: Int32? = nil, continueInBackground: Bool = false) -> Signal { + return Signal { subscriber in + let location: MultipartFetchMasterLocation + if let resource = resource as? WebFileReferenceMediaResource { + location = .web(Int32(datacenterId), resource.apiInputLocation) + } else { + location = .generic(Int32(datacenterId), { resource, resourceReference, fileReference in + if let resource = resource as? TelegramCloudMediaResource { + if let location = resource.apiInputLocation(fileReference: fileReference) { + return .location(location) + } else { + return .none + } + } else if let resource = resource as? CloudPeerPhotoSizeMediaResource { + guard let info = parameters?.info as? TelegramCloudMediaResourceFetchInfo else { + return .none + } + switch resourceReference ?? info.reference { + case let .avatar(peer, _): + if let location = resource.apiInputLocation(peerReference: peer) { + return .location(location) + } else { + return .none + } + case .messageAuthorAvatar: + + return .revalidate + default: + return .none + } + } else if let resource = resource as? CloudStickerPackThumbnailMediaResource { + guard let info = parameters?.info as? TelegramCloudMediaResourceFetchInfo else { + return .none + } + switch info.reference { + case let .stickerPackThumbnail(stickerPack, _): + if let location = resource.apiInputLocation(packReference: stickerPack) { + return .location(location) + } else { + return .none + } + default: + return .none + } + } else { + return .none + } + }) + } + + if encryptionKey != nil { + subscriber.putNext(.reset) + } + + let manager = MultipartFetchManager(resource: resource, parameters: parameters, size: size, intervals: intervals, encryptionKey: encryptionKey, decryptedSize: decryptedSize, location: location, postbox: postbox, network: network, revalidationContext: mediaReferenceRevalidationContext, partReady: { dataOffset, data in + subscriber.putNext(.dataPart(resourceOffset: dataOffset, data: data, range: 0 ..< data.count, complete: false)) + }, reportCompleteSize: { size in + subscriber.putNext(.resourceSizeUpdated(size)) + subscriber.putCompletion() + }) + + manager.start() + + var managerRef: MultipartFetchManager? = manager + + return ActionDisposable { + managerRef?.cancel() + managerRef = nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/MultipartUpload.swift b/submodules/TelegramCore/TelegramCore/MultipartUpload.swift new file mode 100644 index 0000000000..56690081a3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MultipartUpload.swift @@ -0,0 +1,485 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif +import TelegramCorePrivateModule + +#if os(macOS) + private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else + private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +public final class SecretFileEncryptionKey: PostboxCoding, Equatable { + public let aesKey: Data + public let aesIv: Data + + public init(aesKey: Data, aesIv: Data) { + self.aesKey = aesKey + self.aesIv = aesIv + } + + public init(decoder: PostboxDecoder) { + self.aesKey = decoder.decodeBytesForKey("k")!.makeData() + self.aesIv = decoder.decodeBytesForKey("i")!.makeData() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeBytes(MemoryBuffer(data: self.aesKey), forKey: "k") + encoder.encodeBytes(MemoryBuffer(data: self.aesIv), forKey: "i") + } + + public static func ==(lhs: SecretFileEncryptionKey, rhs: SecretFileEncryptionKey) -> Bool { + return lhs.aesKey == rhs.aesKey && lhs.aesIv == rhs.aesIv + } +} + +private struct UploadPart { + let fileId: Int64 + let index: Int + let data: Data + let bigTotalParts: Int? + let bigPart: Bool +} + +private func md5(_ data: Data) -> Data { + return data.withUnsafeBytes { bytes -> Data in + return CryptoMD5(bytes, Int32(data.count)) + } +} + +private final class MultipartUploadState { + let aesKey: Data + var aesIv: Data + var effectiveSize: Int = 0 + + init(encryptionKey: SecretFileEncryptionKey?) { + if let encryptionKey = encryptionKey { + self.aesKey = encryptionKey.aesKey + self.aesIv = encryptionKey.aesIv + } else { + self.aesKey = Data() + self.aesIv = Data() + } + } + + func transformHeader(data: Data) -> Data { + assert(self.aesKey.isEmpty) + self.effectiveSize += data.count + return data + } + + func transform(data: Data) -> Data { + if self.aesKey.count != 0 { + var encryptedData = data + var paddingSize = 0 + while (encryptedData.count + paddingSize) % 16 != 0 { + paddingSize += 1 + } + if paddingSize != 0 { + encryptedData.count = encryptedData.count + paddingSize + } + let encryptedDataCount = encryptedData.count + encryptedData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + if paddingSize != 0 { + arc4random_buf(bytes.advanced(by: encryptedDataCount - paddingSize), paddingSize) + } + self.aesIv.withUnsafeMutableBytes { (iv: UnsafeMutablePointer) -> Void in + MTAesEncryptBytesInplaceAndModifyIv(bytes, encryptedDataCount, self.aesKey, iv) + } + } + self.effectiveSize += encryptedData.count + return encryptedData + } else { + self.effectiveSize += data.count + return data + } + } + + func finalize() -> Int { + return self.effectiveSize + } +} + +private struct MultipartIntermediateResult { + let id: Int64 + let partCount: Int32 + let md5Digest: String + let size: Int32 + let bigTotalParts: Int? +} + +private enum MultipartUploadData { + case resourceData(MediaResourceData) + case data(Data) + + var size: Int { + switch self { + case let .resourceData(data): + return data.size + case let .data(data): + return data.count + } + } + var complete: Bool { + switch self { + case let .resourceData(data): + return data.complete + case .data: + return true + } + } +} + +private enum HeaderPartState { + case notStarted + case uploading + case ready +} + +private final class MultipartUploadManager { + let parallelParts: Int = 3 + var defaultPartSize: Int + var bigTotalParts: Int? + var bigParts: Bool + + let queue = Queue() + let fileId: Int64 + + let dataSignal: Signal + + var committedOffset: Int + let uploadPart: (UploadPart) -> Signal + let progress: (Float) -> Void + let completed: (MultipartIntermediateResult?) -> Void + + var uploadingParts: [Int: (Int, Disposable)] = [:] + var uploadedParts: [Int: Int] = [:] + + let dataDisposable = MetaDisposable() + var resourceData: MultipartUploadData? + + var headerPartState: HeaderPartState + + let state: MultipartUploadState + + init(headerSize: Int32, data: Signal, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, uploadPart: @escaping (UploadPart) -> Signal, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) { + self.dataSignal = data + + var fileId: Int64 = 0 + arc4random_buf(&fileId, 8) + self.fileId = fileId + + self.state = MultipartUploadState(encryptionKey: encryptionKey) + + self.committedOffset = 0 + self.uploadPart = uploadPart + self.progress = progress + self.completed = completed + + if headerSize == 0 { + self.headerPartState = .ready + } else { + self.headerPartState = .notStarted + } + + if let hintFileSize = hintFileSize, hintFileSize > 10 * 1024 * 1024 { + self.defaultPartSize = 512 * 1024 + self.bigTotalParts = (hintFileSize / self.defaultPartSize) + (hintFileSize % self.defaultPartSize == 0 ? 0 : 1) + self.bigParts = true + } else if hintFileIsLarge { + self.defaultPartSize = 512 * 1024 + self.bigTotalParts = nil + self.bigParts = true + } else { + self.bigParts = false + self.defaultPartSize = 16 * 1024 + self.bigTotalParts = nil + } + } + + func start() { + self.queue.async { + self.dataDisposable.set((self.dataSignal + |> deliverOn(self.queue)).start(next: { [weak self] data in + if let strongSelf = self { + strongSelf.resourceData = data + strongSelf.checkState() + } + })) + } + } + + func cancel() { + self.queue.async { + for (_, (_, disposable)) in self.uploadingParts { + disposable.dispose() + } + } + } + + func checkState() { + if let resourceData = self.resourceData, resourceData.complete && resourceData.size != 0 { + if self.committedOffset == 0 && self.uploadedParts.isEmpty && self.uploadingParts.isEmpty { + if resourceData.size > 10 * 1024 * 1024 { + self.defaultPartSize = 512 * 1024 + self.bigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1) + self.bigParts = true + } else { + self.bigParts = false + self.defaultPartSize = 16 * 1024 + self.bigTotalParts = nil + } + } + } + + var updatedCommittedOffset = false + for offset in self.uploadedParts.keys.sorted() { + if offset == self.committedOffset { + let partSize = self.uploadedParts[offset]! + self.committedOffset += partSize + updatedCommittedOffset = true + let _ = self.uploadedParts.removeValue(forKey: offset) + } + } + if updatedCommittedOffset { + if let resourceData = self.resourceData, resourceData.complete && resourceData.size != 0 { + self.progress(Float(self.committedOffset) / Float(resourceData.size)) + } + } + + if let resourceData = self.resourceData, resourceData.complete, self.committedOffset >= resourceData.size { + switch self.headerPartState { + case .ready: + let effectiveSize = self.state.finalize() + let effectivePartCount = Int32(effectiveSize / self.defaultPartSize + (effectiveSize % self.defaultPartSize == 0 ? 0 : 1)) + var currentBigTotalParts = self.bigTotalParts + if self.bigParts { + currentBigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1) + } + self.completed(MultipartIntermediateResult(id: self.fileId, partCount: effectivePartCount, md5Digest: "", size: Int32(resourceData.size), bigTotalParts: currentBigTotalParts)) + case .notStarted: + let partOffset = 0 + let partSize = min(resourceData.size - partOffset, self.defaultPartSize) + let partIndex = partOffset / self.defaultPartSize + let fileData: Data? + switch resourceData { + case let .resourceData(data): + fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.alwaysMapped]) + case let .data(data): + fileData = data + } + if let fileData = fileData { + let partData = self.state.transformHeader(data: fileData.subdata(in: partOffset ..< (partOffset + partSize))) + var currentBigTotalParts: Int? = nil + if self.bigParts { + let totalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1) + currentBigTotalParts = totalParts + } + self.headerPartState = .uploading + let part = self.uploadPart(UploadPart(fileId: self.fileId, index: partIndex, data: partData, bigTotalParts: currentBigTotalParts, bigPart: self.bigParts)) + |> deliverOn(self.queue) + self.uploadingParts[0] = (partSize, part.start(error: { [weak self] _ in + self?.completed(nil) + }, completed: { [weak self] in + if let strongSelf = self { + let _ = strongSelf.uploadingParts.removeValue(forKey: 0) + strongSelf.headerPartState = .ready + strongSelf.checkState() + } + })) + } + case .uploading: + break + } + } else if let resourceData = self.resourceData, self.state.aesKey.isEmpty || resourceData.complete { + while uploadingParts.count < self.parallelParts { + switch self.headerPartState { + case .notStarted: + if self.committedOffset == 0, !resourceData.complete { + self.committedOffset += self.defaultPartSize + } + case .ready, .uploading: + break + } + + var nextOffset = self.committedOffset + for (offset, (size, _)) in self.uploadingParts { + nextOffset = max(nextOffset, offset + size) + } + for (offset, partSize) in self.uploadedParts { + nextOffset = max(nextOffset, offset + partSize) + } + + let partOffset = nextOffset + let partSize = min(resourceData.size - partOffset, self.defaultPartSize) + + if nextOffset < resourceData.size && partSize > 0 && (resourceData.complete || partSize == self.defaultPartSize) { + let partIndex = partOffset / self.defaultPartSize + let fileData: Data? + switch resourceData { + case let .resourceData(data): + fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.alwaysMapped]) + case let .data(data): + fileData = data + } + if let fileData = fileData, fileData.count >= partOffset + partSize { + let partData = self.state.transform(data: fileData.subdata(in: partOffset ..< (partOffset + partSize))) + var currentBigTotalParts = self.bigTotalParts + if self.bigParts && resourceData.complete && partOffset + partSize == resourceData.size { + currentBigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1) + } + let part = self.uploadPart(UploadPart(fileId: self.fileId, index: partIndex, data: partData, bigTotalParts: currentBigTotalParts, bigPart: self.bigParts)) + |> deliverOn(self.queue) + if partIndex == 0 { + switch self.headerPartState { + case .notStarted: + self.headerPartState = .uploading + case .ready, .uploading: + break + } + } + self.uploadingParts[nextOffset] = (partSize, part.start(error: { [weak self] _ in + self?.completed(nil) + }, completed: { [weak self] in + if let strongSelf = self { + let _ = strongSelf.uploadingParts.removeValue(forKey: nextOffset) + strongSelf.uploadedParts[partOffset] = partSize + if partIndex == 0 { + strongSelf.headerPartState = .ready + } + strongSelf.checkState() + } + })) + } else { + self.completed(nil) + } + } else { + break + } + } + } + } +} + +enum MultipartUploadResult { + case progress(Float) + case inputFile(Api.InputFile) + case inputSecretFile(Api.InputEncryptedFile, Int32, SecretFileEncryptionKey) +} + +public enum MultipartUploadSource { + case resource(MediaResourceReference) + case data(Data) + case custom(Signal) +} + +enum MultipartUploadError { + case generic +} + +func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool) -> Signal { + return network.upload(tag: tag) + |> mapToSignalPromotingError { download -> Signal in + return Signal { subscriber in + var encryptionKey: SecretFileEncryptionKey? + if encrypt { + var aesKey = Data() + aesKey.count = 32 + var aesIv = Data() + aesIv.count = 32 + aesKey.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, 32) + } + aesIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, 32) + } + encryptionKey = SecretFileEncryptionKey(aesKey: aesKey, aesIv: aesIv) + } + + let dataSignal: Signal + let headerSize: Int32 + let fetchedResource: Signal + switch source { + case let .resource(resource): + dataSignal = postbox.mediaBox.resourceData(resource.resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) } + headerSize = resource.resource.headerSize + fetchedResource = fetchedMediaResource(postbox: postbox, reference: resource) + |> map { _ in } + case let .data(data): + dataSignal = .single(.data(data)) + headerSize = 0 + fetchedResource = .complete() + case let .custom(signal): + headerSize = 1024 + dataSignal = signal + |> map { data in + print("**data \(data) \(data.complete)") + return MultipartUploadData.resourceData(data) + } + fetchedResource = .complete() + } + + let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, uploadPart: { part in + return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts) + }, progress: { progress in + subscriber.putNext(.progress(progress)) + }, completed: { result in + if let result = result { + if let encryptionKey = encryptionKey { + let keyDigest = md5(encryptionKey.aesKey + encryptionKey.aesIv) + var fingerprint: Int32 = 0 + keyDigest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + withUnsafeMutableBytes(of: &fingerprint, { ptr -> Void in + let uintPtr = ptr.baseAddress!.assumingMemoryBound(to: UInt8.self) + uintPtr[0] = bytes[0] ^ bytes[4] + uintPtr[1] = bytes[1] ^ bytes[5] + uintPtr[2] = bytes[2] ^ bytes[6] + uintPtr[3] = bytes[3] ^ bytes[7] + }) + } + if let _ = result.bigTotalParts { + let inputFile = Api.InputEncryptedFile.inputEncryptedFileBigUploaded(id: result.id, parts: result.partCount, keyFingerprint: fingerprint) + subscriber.putNext(.inputSecretFile(inputFile, result.size, encryptionKey)) + } else { + let inputFile = Api.InputEncryptedFile.inputEncryptedFileUploaded(id: result.id, parts: result.partCount, md5Checksum: result.md5Digest, keyFingerprint: fingerprint) + subscriber.putNext(.inputSecretFile(inputFile, result.size, encryptionKey)) + } + } else { + if let _ = result.bigTotalParts { + let inputFile = Api.InputFile.inputFileBig(id: result.id, parts: result.partCount, name: "file.jpg") + subscriber.putNext(.inputFile(inputFile)) + } else { + let inputFile = Api.InputFile.inputFile(id: result.id, parts: result.partCount, name: "file.jpg", md5Checksum: result.md5Digest) + subscriber.putNext(.inputFile(inputFile)) + } + } + subscriber.putCompletion() + } else { + subscriber.putError(.generic) + } + }) + + manager.start() + + let fetchedResourceDisposable = fetchedResource.start(error: { _ in + subscriber.putError(.generic) + }) + + return ActionDisposable { + manager.cancel() + fetchedResourceDisposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/MultipeerManager.swift b/submodules/TelegramCore/TelegramCore/MultipeerManager.swift new file mode 100644 index 0000000000..90004e3427 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MultipeerManager.swift @@ -0,0 +1,119 @@ +import Foundation +import MultipeerConnectivity + +protocol ColorServiceManagerDelegate { + + func connectedDevicesChanged(manager : ColorServiceManager, connectedDevices: [String]) + func colorChanged(manager : ColorServiceManager, colorString: String) + +} + +class ColorServiceManager : NSObject { + private let ColorServiceType = "tg-p2p" + + private let myPeerId = MCPeerID(displayName: UIDevice.current.name) + + private let serviceAdvertiser : MCNearbyServiceAdvertiser + private let serviceBrowser : MCNearbyServiceBrowser + + var delegate : ColorServiceManagerDelegate? + + lazy var session : MCSession = { + let session = MCSession(peer: self.myPeerId, securityIdentity: nil, encryptionPreference: .required) + session.delegate = self + return session + }() + + override init() { + self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerId, discoveryInfo: nil, serviceType: ColorServiceType) + self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerId, serviceType: ColorServiceType) + + super.init() + + self.serviceAdvertiser.delegate = self + self.serviceAdvertiser.startAdvertisingPeer() + + self.serviceBrowser.delegate = self + self.serviceBrowser.startBrowsingForPeers() + } + + func send(colorName : String) { + NSLog("%@", "sendColor: \(colorName) to \(session.connectedPeers.count) peers") + + if session.connectedPeers.count > 0 { + do { + try self.session.send(colorName.data(using: .utf8)!, toPeers: session.connectedPeers, with: .reliable) + } + catch let error { + NSLog("%@", "Error for sending: \(error)") + } + } + + } + + deinit { + self.serviceAdvertiser.stopAdvertisingPeer() + self.serviceBrowser.stopBrowsingForPeers() + } + +} + +extension ColorServiceManager : MCNearbyServiceAdvertiserDelegate { + + func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didNotStartAdvertisingPeer error: Error) { + NSLog("%@", "didNotStartAdvertisingPeer: \(error)") + } + + func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) { + NSLog("%@", "didReceiveInvitationFromPeer \(peerID)") + invitationHandler(true, self.session) + } + +} + +extension ColorServiceManager : MCNearbyServiceBrowserDelegate { + + func browser(_ browser: MCNearbyServiceBrowser, didNotStartBrowsingForPeers error: Error) { + NSLog("%@", "didNotStartBrowsingForPeers: \(error)") + } + + func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) { + NSLog("%@", "foundPeer: \(peerID)") + NSLog("%@", "invitePeer: \(peerID)") + browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 10) + } + + func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { + NSLog("%@", "lostPeer: \(peerID)") + } + +} + +extension ColorServiceManager : MCSessionDelegate { + + func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) { + NSLog("%@", "peer \(peerID) didChangeState: \(state)") + self.delegate?.connectedDevicesChanged(manager: self, connectedDevices: + session.connectedPeers.map{$0.displayName}) + } + + func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { + NSLog("%@", "didReceiveData: \(data)") + let str = String(data: data, encoding: .utf8)! + self.delegate?.colorChanged(manager: self, colorString: str) + } + + func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { + NSLog("%@", "didReceiveStream") + } + + func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) { + NSLog("%@", "didStartReceivingResourceWithName") + } + + func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) { + NSLog("%@", "didFinishReceivingResourceWithName") + } + +} + diff --git a/submodules/TelegramCore/TelegramCore/MultiplexedRequestManager.swift b/submodules/TelegramCore/TelegramCore/MultiplexedRequestManager.swift new file mode 100644 index 0000000000..cf73d0df7c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/MultiplexedRequestManager.swift @@ -0,0 +1,302 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +enum MultiplexedRequestTarget: Equatable, Hashable { + case main(Int) + case cdn(Int) +} + +private struct MultiplexedRequestTargetKey: Equatable, Hashable { + let target: MultiplexedRequestTarget + let continueInBackground: Bool +} + +private final class RequestData { + let id: Int32 + let consumerId: Int64 + let target: MultiplexedRequestTarget + let functionDescription: FunctionDescription + let payload: Buffer + let tag: MediaResourceFetchTag? + let continueInBackground: Bool + let deserializeResponse: (Buffer) -> Any? + let completed: (Any) -> Void + let error: (MTRpcError) -> Void + + init(id: Int32, consumerId: Int64, target: MultiplexedRequestTarget, functionDescription: FunctionDescription, payload: Buffer, tag: MediaResourceFetchTag?, continueInBackground: Bool, deserializeResponse: @escaping (Buffer) -> Any?, completed: @escaping (Any) -> Void, error: @escaping (MTRpcError) -> Void) { + self.id = id + self.consumerId = consumerId + self.target = target + self.functionDescription = functionDescription + self.tag = tag + self.continueInBackground = continueInBackground + self.payload = payload + self.deserializeResponse = deserializeResponse + self.completed = completed + self.error = error + } +} + +private final class ExecutingRequestData { + let requestId: Int32 + let disposable: Disposable + + init(requestId: Int32, disposable: Disposable) { + self.requestId = requestId + self.disposable = disposable + } +} + +private final class RequestTargetContext { + let id: Int32 + let worker: Download + var requests: [ExecutingRequestData] + + init(id: Int32, worker: Download) { + self.id = id + self.worker = worker + self.requests = [] + } +} + +private struct MultiplexedRequestTargetTimerKey: Equatable, Hashable { + let key: MultiplexedRequestTargetKey + let id: Int32 +} + +#if os(macOS) +private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else +private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private final class MultiplexedRequestManagerContext { + private let queue: Queue + private let takeWorker: (MultiplexedRequestTarget, MediaResourceFetchTag?, Bool) -> Download? + + private var queuedRequests: [RequestData] = [] + private var nextId: Int32 = 0 + + private var targetContexts: [MultiplexedRequestTargetKey: [RequestTargetContext]] = [:] + private var emptyTargetTimers: [MultiplexedRequestTargetTimerKey: SignalKitTimer] = [:] + + init(queue: Queue, takeWorker: @escaping (MultiplexedRequestTarget, MediaResourceFetchTag?, Bool) -> Download?) { + self.queue = queue + self.takeWorker = takeWorker + } + + deinit { + for targetContextList in self.targetContexts.values { + for targetContext in targetContextList { + for request in targetContext.requests { + request.disposable.dispose() + } + } + } + for timer in emptyTargetTimers.values { + timer.invalidate() + } + } + + func request(to target: MultiplexedRequestTarget, consumerId: Int64, data: (FunctionDescription, Buffer, (Buffer) -> Any?), tag: MediaResourceFetchTag?, continueInBackground: Bool, completed: @escaping (Any) -> Void, error: @escaping (MTRpcError) -> Void) -> Disposable { + let targetKey = MultiplexedRequestTargetKey(target: target, continueInBackground: continueInBackground) + + let requestId = self.nextId + self.nextId += 1 + self.queuedRequests.append(RequestData(id: requestId, consumerId: consumerId, target: target, functionDescription: data.0, payload: data.1, tag: tag, continueInBackground: continueInBackground, deserializeResponse: { buffer in + return data.2(buffer) + }, completed: { result in + completed(result) + }, error: { e in + error(e) + })) + + self.updateState() + + let queue = self.queue + return ActionDisposable { [weak self] in + queue.async { + guard let strongSelf = self else { + return + } + for i in 0 ..< strongSelf.queuedRequests.count { + if strongSelf.queuedRequests[i].id == requestId { + strongSelf.queuedRequests.remove(at: i) + break + } + } + + if strongSelf.targetContexts[targetKey] != nil { + outer: for targetContext in strongSelf.targetContexts[targetKey]! { + for i in 0 ..< targetContext.requests.count { + if targetContext.requests[i].requestId == requestId { + targetContext.requests[i].disposable.dispose() + targetContext.requests.remove(at: i) + break outer + } + } + } + } + + strongSelf.updateState() + } + } + } + + private func updateState() { + let maxRequestsPerWorker = 2 + let maxWorkersPerTarget = 4 + + var requestIndex = 0 + while requestIndex < self.queuedRequests.count { + let request = self.queuedRequests[requestIndex] + let targetKey = MultiplexedRequestTargetKey(target: request.target, continueInBackground: request.continueInBackground) + + if self.targetContexts[targetKey] == nil { + self.targetContexts[targetKey] = [] + } + var selectedContext: RequestTargetContext? + for targetContext in self.targetContexts[targetKey]! { + if targetContext.requests.count < maxRequestsPerWorker { + selectedContext = targetContext + break + } + } + if selectedContext == nil && self.targetContexts[targetKey]!.count < maxWorkersPerTarget { + if let worker = self.takeWorker(request.target, request.tag, request.continueInBackground) { + let contextId = self.nextId + self.nextId += 1 + let targetContext = RequestTargetContext(id: contextId, worker: worker) + self.targetContexts[targetKey]!.append(targetContext) + selectedContext = targetContext + } else { + Logger.shared.log("MultiplexedRequestManager", "couldn't take worker") + } + } + if let selectedContext = selectedContext { + let disposable = MetaDisposable() + let requestId = request.id + selectedContext.requests.append(ExecutingRequestData(requestId: requestId, disposable: disposable)) + let queue = self.queue + disposable.set(selectedContext.worker.rawRequest((request.functionDescription, request.payload, request.deserializeResponse)).start(next: { [weak self, weak selectedContext] result in + queue.async { + guard let strongSelf = self else { + return + } + if let selectedContext = selectedContext { + for i in 0 ..< selectedContext.requests.count { + if selectedContext.requests[i].requestId == requestId { + selectedContext.requests.remove(at: i) + break + } + } + } + request.completed(result) + strongSelf.updateState() + } + }, error: { [weak self, weak selectedContext] error in + queue.async { + guard let strongSelf = self else { + return + } + request.error(error) + if let selectedContext = selectedContext { + for i in 0 ..< selectedContext.requests.count { + if selectedContext.requests[i].requestId == requestId { + selectedContext.requests.remove(at: i) + break + } + } + } + strongSelf.updateState() + } + })) + + self.queuedRequests.remove(at: requestIndex) + continue + } + + requestIndex += 1 + } + + self.checkEmptyContexts() + } + + private func checkEmptyContexts() { + for (targetKey, contexts) in self.targetContexts { + for context in contexts { + let key = MultiplexedRequestTargetTimerKey(key: targetKey, id: context.id) + if context.requests.isEmpty { + if self.emptyTargetTimers[key] == nil { + let timer = SignalKitTimer(timeout: 2.0, repeat: false, completion: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.emptyTargetTimers.removeValue(forKey: key) + if strongSelf.targetContexts[targetKey] != nil { + for i in 0 ..< strongSelf.targetContexts[targetKey]!.count { + if strongSelf.targetContexts[targetKey]![i].id == key.id { + strongSelf.targetContexts[targetKey]!.remove(at: i) + break + } + } + } + }, queue: self.queue) + self.emptyTargetTimers[key] = timer + timer.start() + } + } else { + if let timer = self.emptyTargetTimers[key] { + timer.invalidate() + self.emptyTargetTimers.removeValue(forKey: key) + } + } + } + } + } +} + +final class MultiplexedRequestManager { + private let queue = Queue() + private let context: QueueLocalObject + + init(takeWorker: @escaping (MultiplexedRequestTarget, MediaResourceFetchTag?, Bool) -> Download?) { + let queue = self.queue + self.context = QueueLocalObject(queue: self.queue, generate: { + return MultiplexedRequestManagerContext(queue: queue, takeWorker: takeWorker) + }) + } + + func request(to target: MultiplexedRequestTarget, consumerId: Int64, data: (FunctionDescription, Buffer, DeserializeFunctionResponse), tag: MediaResourceFetchTag?, continueInBackground: Bool) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.context.with { context in + disposable.set(context.request(to: target, consumerId: consumerId, data: (data.0, data.1, { buffer in + return data.2.parse(buffer) + }), tag: tag, continueInBackground: continueInBackground, completed: { result in + if let result = result as? T { + subscriber.putNext(result) + subscriber.putCompletion() + } else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + }, error: { error in + subscriber.putError(error) + })) + } + return disposable + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Namespaces.swift b/submodules/TelegramCore/TelegramCore/Namespaces.swift new file mode 100644 index 0000000000..15007d023b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Namespaces.swift @@ -0,0 +1,296 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct Namespaces { + public struct Message { + public static let Cloud: Int32 = 0 + public static let Local: Int32 = 1 + public static let SecretIncoming: Int32 = 2 + } + + public struct Media { + public static let CloudImage: Int32 = 0 + public static let CloudAudio: Int32 = 2 + public static let CloudContact: Int32 = 3 + public static let CloudMap: Int32 = 4 + public static let CloudFile: Int32 = 5 + public static let CloudWebpage: Int32 = 6 + public static let LocalImage: Int32 = 7 + public static let LocalFile: Int32 = 8 + public static let CloudSecretImage: Int32 = 9 + public static let CloudSecretFile: Int32 = 10 + public static let CloudGame: Int32 = 11 + public static let CloudInvoice: Int32 = 12 + public static let LocalWebpage: Int32 = 13 + public static let LocalPoll: Int32 = 14 + public static let CloudPoll: Int32 = 15 + } + + public struct Peer { + public static let CloudUser: Int32 = 0 + public static let CloudGroup: Int32 = 1 + public static let CloudChannel: Int32 = 2 + public static let SecretChat: Int32 = 3 + public static let Empty: Int32 = Int32.max + } + + public struct ItemCollection { + public static let CloudStickerPacks: Int32 = 0 + public static let CloudMaskPacks: Int32 = 1 + public static let EmojiKeywords: Int32 = 2 + } + + public struct OrderedItemList { + public static let CloudRecentStickers: Int32 = 0 + public static let CloudRecentGifs: Int32 = 1 + public static let RecentlySearchedPeerIds: Int32 = 2 + public static let CloudRecentInlineBots: Int32 = 3 + public static let CloudFeaturedStickerPacks: Int32 = 4 + public static let CloudArchivedStickerPacks: Int32 = 5 + public static let CloudWallpapers: Int32 = 6 + public static let CloudSavedStickers: Int32 = 7 + public static let RecentlyUsedHashtags: Int32 = 8 + } + + struct CachedItemCollection { + public static let resolvedByNamePeers: Int8 = 0 + public static let cachedTwoStepToken: Int8 = 1 + public static let cachedStickerPacks: Int8 = 2 + public static let cachedAvailableLocalizations: Int8 = 3 + public static let cachedSentMediaReferences: Int8 = 4 + public static let cachedStickerQueryResults: Int8 = 5 + public static let cachedSecureIdConfiguration: Int8 = 6 + public static let cachedWallpapersConfiguration: Int8 = 7 + } + + struct UnorderedItemList { + static let synchronizedDeviceContacts: UnorderedItemListEntryTag = { + let key = ValueBoxKey(length: 1) + key.setUInt8(0, value: 0) + return UnorderedItemListEntryTag(value: key) + }() + } + + public struct PeerGroup { + public static let archive = PeerGroupId(rawValue: 1) + } +} + +public extension MessageTags { + static let photoOrVideo = MessageTags(rawValue: 1 << 0) + static let file = MessageTags(rawValue: 1 << 1) + static let music = MessageTags(rawValue: 1 << 2) + static let webPage = MessageTags(rawValue: 1 << 3) + static let voiceOrInstantVideo = MessageTags(rawValue: 1 << 4) + static let unseenPersonalMessage = MessageTags(rawValue: 1 << 5) + static let liveLocation = MessageTags(rawValue: 1 << 6) + + static let all: MessageTags = [.photoOrVideo, .file, .music, .webPage, .voiceOrInstantVideo, .unseenPersonalMessage, .liveLocation] +} + +public extension GlobalMessageTags { + static let Calls = GlobalMessageTags(rawValue: 1 << 0) + static let MissedCalls = GlobalMessageTags(rawValue: 1 << 1) + + static let all: GlobalMessageTags = [.Calls, .MissedCalls] +} + +public extension LocalMessageTags { + static let OutgoingLiveLocation = LocalMessageTags(rawValue: 1 << 0) + static let OutgoingDeliveredToServer = LocalMessageTags(rawValue: 1 << 1) +} + +public extension PendingMessageActionType { + static let consumeUnseenPersonalMessage = PendingMessageActionType(rawValue: 0) +} + +let peerIdNamespacesWithInitialCloudMessageHoles = [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel] + +public struct OperationLogTags { + public static let SecretOutgoing = PeerOperationLogTag(value: 0) + static let SecretIncomingEncrypted = PeerOperationLogTag(value: 1) + static let SecretIncomingDecrypted = PeerOperationLogTag(value: 2) + static let CloudChatRemoveMessages = PeerOperationLogTag(value: 3) + static let SynchronizePinnedCloudChats = PeerOperationLogTag(value: 4) + static let AutoremoveMessages = PeerOperationLogTag(value: 5) + static let SynchronizePinnedChats = PeerOperationLogTag(value: 6) + static let SynchronizeConsumeMessageContents = PeerOperationLogTag(value: 7) + static let SynchronizeInstalledStickerPacks = PeerOperationLogTag(value: 8) + static let SynchronizeInstalledMasks = PeerOperationLogTag(value: 9) + static let SynchronizeMarkFeaturedStickerPacksAsSeen = PeerOperationLogTag(value: 10) + static let SynchronizeChatInputStates = PeerOperationLogTag(value: 11) + static let SynchronizeSavedGifs = PeerOperationLogTag(value: 12) + static let SynchronizeLocalizationUpdates = PeerOperationLogTag(value: 13) + static let SynchronizeSavedStickers = PeerOperationLogTag(value: 14) + static let SynchronizeGroupedPeers = PeerOperationLogTag(value: 15) + static let SynchronizeMarkAllUnseenPersonalMessages = PeerOperationLogTag(value: 16) + static let SynchronizeRecentlyUsedStickers = PeerOperationLogTag(value: 17) + static let SynchronizeAppLogEvents = PeerOperationLogTag(value: 18) + static let SynchronizeEmojiKeywords = PeerOperationLogTag(value: 19) +} + +public extension PeerSummaryCounterTags { + public static let regularChatsAndPrivateGroups = PeerSummaryCounterTags(rawValue: 1 << 0) + public static let publicGroups = PeerSummaryCounterTags(rawValue: 1 << 1) + public static let channels = PeerSummaryCounterTags(rawValue: 1 << 2) +} + +private enum PreferencesKeyValues: Int32 { + case globalNotifications = 0 + case suggestedLocalization = 3 + case limitsConfiguration = 4 + case coreSettings = 7 + case contentPrivacySettings = 8 + case networkSettings = 9 + case remoteStorageConfiguration = 10 + case voipConfiguration = 11 + case appChangelogState = 12 + case localizationListState = 13 + case appConfiguration = 14 + case searchBotsConfiguration = 15 + case contactsSettings = 16 +} + +public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: value + 1000) + return key +} + +public func applicationSpecificSharedDataKey(_ value: Int32) -> ValueBoxKey { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: value + 1000) + return key +} + +public struct PreferencesKeys { + public static let globalNotifications: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.globalNotifications.rawValue) + return key + }() + + public static let suggestedLocalization: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.suggestedLocalization.rawValue) + return key + }() + + public static let limitsConfiguration: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.limitsConfiguration.rawValue) + return key + }() + + public static let coreSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.coreSettings.rawValue) + return key + }() + + public static let contentPrivacySettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.contentPrivacySettings.rawValue) + return key + }() + + public static let networkSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.networkSettings.rawValue) + return key + }() + + public static let remoteStorageConfiguration: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.remoteStorageConfiguration.rawValue) + return key + }() + + public static let voipConfiguration: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.voipConfiguration.rawValue) + return key + }() + + public static let appChangelogState: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.appChangelogState.rawValue) + return key + }() + + public static let localizationListState: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.localizationListState.rawValue) + return key + }() + + public static let appConfiguration: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.appConfiguration.rawValue) + return key + }() + + public static let searchBotsConfiguration: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.searchBotsConfiguration.rawValue) + return key + }() + + public static let contactsSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.contactsSettings.rawValue) + return key + }() +} + +private enum SharedDataKeyValues: Int32 { + case loggingSettings = 0 + case cacheStorageSettings = 2 + case localizationSettings = 3 + case proxySettings = 4 + case autodownloadSettings = 5 +} + +public struct SharedDataKeys { + public static let loggingSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.loggingSettings.rawValue) + return key + }() + + public static let cacheStorageSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.cacheStorageSettings.rawValue) + return key + }() + + public static let localizationSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.localizationSettings.rawValue) + return key + }() + + public static let proxySettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.proxySettings.rawValue) + return key + }() + + public static let autodownloadSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.autodownloadSettings.rawValue) + return key + }() +} + +public func applicationSpecificItemCacheCollectionId(_ value: Int8) -> Int8 { + return 64 + value +} + +public func applicationSpecificOrderedItemListCollectionId(_ value: Int32) -> Int32 { + return 1000 + value +} diff --git a/submodules/TelegramCore/TelegramCore/Network.swift b/submodules/TelegramCore/TelegramCore/Network.swift new file mode 100644 index 0000000000..384aa03b7c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Network.swift @@ -0,0 +1,985 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif +import TelegramCorePrivateModule + +public enum ConnectionStatus: Equatable { + case waitingForNetwork + case connecting(proxyAddress: String?, proxyHasConnectionIssues: Bool) + case updating(proxyAddress: String?) + case online(proxyAddress: String?) +} + +private struct MTProtoConnectionFlags: OptionSet { + let rawValue: Int + + static let NetworkAvailable = MTProtoConnectionFlags(rawValue: 1) + static let Connected = MTProtoConnectionFlags(rawValue: 2) + static let UpdatingConnectionContext = MTProtoConnectionFlags(rawValue: 4) + static let PerformingServiceTasks = MTProtoConnectionFlags(rawValue: 8) + static let ProxyHasConnectionIssues = MTProtoConnectionFlags(rawValue: 16) +} + +private struct MTProtoConnectionInfo: Equatable { + var flags: MTProtoConnectionFlags + var proxyAddress: String? +} + +final class WrappedFunctionDescription: CustomStringConvertible { + private let desc: FunctionDescription + + init(_ desc: FunctionDescription) { + self.desc = desc + } + + var description: String { + return apiFunctionDescription(of: self.desc) + } +} + +final class WrappedShortFunctionDescription: CustomStringConvertible { + private let desc: FunctionDescription + + init(_ desc: FunctionDescription) { + self.desc = desc + } + + var description: String { + return apiShortFunctionDescription(of: self.desc) + } +} + +class WrappedRequestMetadata: NSObject { + let metadata: CustomStringConvertible + let tag: NetworkRequestDependencyTag? + + init(metadata: CustomStringConvertible, tag: NetworkRequestDependencyTag?) { + self.metadata = metadata + self.tag = tag + } + + override var description: String { + return self.metadata.description + } +} + +class WrappedRequestShortMetadata: NSObject { + let shortMetadata: CustomStringConvertible + + init(shortMetadata: CustomStringConvertible) { + self.shortMetadata = shortMetadata + } + + override var description: String { + return self.shortMetadata.description + } +} + +public protocol NetworkRequestDependencyTag { + func shouldDependOn(other: NetworkRequestDependencyTag) -> Bool +} + +private class MTProtoConnectionStatusDelegate: NSObject, MTProtoDelegate { + var action: (MTProtoConnectionInfo) -> () = { _ in } + let info = Atomic(value: MTProtoConnectionInfo(flags: [], proxyAddress: nil)) + + @objc func mtProtoNetworkAvailabilityChanged(_ mtProto: MTProto!, isNetworkAvailable: Bool) { + self.action(self.info.modify { info in + var info = info + if isNetworkAvailable { + info.flags = info.flags.union([.NetworkAvailable]) + } else { + info.flags = info.flags.subtracting([.NetworkAvailable]) + } + return info + }) + } + + @objc func mtProtoConnectionStateChanged(_ mtProto: MTProto!, state: MTProtoConnectionState!) { + self.action(self.info.modify { info in + var info = info + if let state = state { + if state.isConnected { + info.flags.insert(.Connected) + info.flags.remove(.ProxyHasConnectionIssues) + } else { + info.flags.remove(.Connected) + if state.proxyHasConnectionIssues { + info.flags.insert(.ProxyHasConnectionIssues) + } else { + info.flags.remove(.ProxyHasConnectionIssues) + } + } + } else { + info.flags.remove(.Connected) + info.flags.remove(.ProxyHasConnectionIssues) + } + info.proxyAddress = state?.proxyAddress + return info + }) + } + + @objc func mtProtoConnectionContextUpdateStateChanged(_ mtProto: MTProto!, isUpdatingConnectionContext: Bool) { + self.action(self.info.modify { info in + var info = info + if isUpdatingConnectionContext { + info.flags = info.flags.union([.UpdatingConnectionContext]) + } else { + info.flags = info.flags.subtracting([.UpdatingConnectionContext]) + } + return info + }) + } + + @objc func mtProtoServiceTasksStateChanged(_ mtProto: MTProto!, isPerformingServiceTasks: Bool) { + self.action(self.info.modify { info in + var info = info + if isPerformingServiceTasks { + info.flags = info.flags.union([.PerformingServiceTasks]) + } else { + info.flags = info.flags.subtracting([.PerformingServiceTasks]) + } + return info + }) + } +} + +private var registeredLoggingFunctions: Void = { + NetworkRegisterLoggingFunction() + registerLoggingFunctions() +}() + +private enum UsageCalculationConnection: Int32 { + case cellular = 0 + case wifi = 1 +} + +private enum UsageCalculationDirection: Int32 { + case incoming = 0 + case outgoing = 1 +} + +private struct UsageCalculationTag { + let connection: UsageCalculationConnection + let direction: UsageCalculationDirection + let category: MediaResourceStatsCategory + + var key: Int32 { + switch category { + case .generic: + return 0 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + case .image: + return 1 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + case .video: + return 2 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + case .audio: + return 3 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + case .file: + return 4 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + case .call: + return 5 * 4 + self.connection.rawValue * 2 + self.direction.rawValue * 1 + } + } +} + +private enum UsageCalculationResetKey: Int32 { + case wifi = 80 //20 * 4 + 0 + case cellular = 81 //20 * 4 + 2 +} + +private func usageCalculationInfo(basePath: String, category: MediaResourceStatsCategory?) -> MTNetworkUsageCalculationInfo { + let categoryValue: MediaResourceStatsCategory + if let category = category { + categoryValue = category + } else { + categoryValue = .generic + } + return MTNetworkUsageCalculationInfo(filePath: basePath + "/network-stats", incomingWWANKey: UsageCalculationTag(connection: .cellular, direction: .incoming, category: categoryValue).key, outgoingWWANKey: UsageCalculationTag(connection: .cellular, direction: .outgoing, category: categoryValue).key, incomingOtherKey: UsageCalculationTag(connection: .wifi, direction: .incoming, category: categoryValue).key, outgoingOtherKey: UsageCalculationTag(connection: .wifi, direction: .outgoing, category: categoryValue).key) +} + +public struct NetworkUsageStatsDirectionsEntry: Equatable { + public let incoming: Int64 + public let outgoing: Int64 + + public init(incoming: Int64, outgoing: Int64) { + self.incoming = incoming + self.outgoing = outgoing + } + + public static func ==(lhs: NetworkUsageStatsDirectionsEntry, rhs: NetworkUsageStatsDirectionsEntry) -> Bool { + return lhs.incoming == rhs.incoming && lhs.outgoing == rhs.outgoing + } +} + +public struct NetworkUsageStatsConnectionsEntry: Equatable { + public let cellular: NetworkUsageStatsDirectionsEntry + public let wifi: NetworkUsageStatsDirectionsEntry + + public init(cellular: NetworkUsageStatsDirectionsEntry, wifi: NetworkUsageStatsDirectionsEntry) { + self.cellular = cellular + self.wifi = wifi + } + + public static func ==(lhs: NetworkUsageStatsConnectionsEntry, rhs: NetworkUsageStatsConnectionsEntry) -> Bool { + return lhs.cellular == rhs.cellular && lhs.wifi == rhs.wifi + } +} + +public struct NetworkUsageStats: Equatable { + public let generic: NetworkUsageStatsConnectionsEntry + public let image: NetworkUsageStatsConnectionsEntry + public let video: NetworkUsageStatsConnectionsEntry + public let audio: NetworkUsageStatsConnectionsEntry + public let file: NetworkUsageStatsConnectionsEntry + public let call: NetworkUsageStatsConnectionsEntry + + public let resetWifiTimestamp: Int32 + public let resetCellularTimestamp: Int32 + + public static func ==(lhs: NetworkUsageStats, rhs: NetworkUsageStats) -> Bool { + return lhs.generic == rhs.generic && lhs.image == rhs.image && lhs.video == rhs.video && lhs.audio == rhs.audio && lhs.file == rhs.file && lhs.call == rhs.call && lhs.resetWifiTimestamp == rhs.resetWifiTimestamp && lhs.resetCellularTimestamp == rhs.resetCellularTimestamp + } +} + +public struct ResetNetworkUsageStats: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let wifi = ResetNetworkUsageStats(rawValue: 1 << 0) + public static let cellular = ResetNetworkUsageStats(rawValue: 1 << 1) +} + +private func interfaceForConnection(_ connection: UsageCalculationConnection) -> MTNetworkUsageManagerInterface { + return MTNetworkUsageManagerInterface(rawValue: UInt32(connection.rawValue)) +} + +func updateNetworkUsageStats(basePath: String, category: MediaResourceStatsCategory, delta: NetworkUsageStatsConnectionsEntry) { + let info = usageCalculationInfo(basePath: basePath, category: category) + let manager = MTNetworkUsageManager(info: info)! + + manager.addIncomingBytes(UInt(clamping: delta.wifi.incoming), interface: interfaceForConnection(.wifi)) + manager.addOutgoingBytes(UInt(clamping: delta.wifi.outgoing), interface: interfaceForConnection(.wifi)) + + manager.addIncomingBytes(UInt(clamping: delta.cellular.incoming), interface: interfaceForConnection(.cellular)) + manager.addOutgoingBytes(UInt(clamping: delta.cellular.outgoing), interface: interfaceForConnection(.cellular)) +} + +func networkUsageStats(basePath: String, reset: ResetNetworkUsageStats) -> Signal { + return ((Signal { subscriber in + let info = usageCalculationInfo(basePath: basePath, category: nil) + let manager = MTNetworkUsageManager(info: info)! + + let rawKeys: [UsageCalculationTag] = [ + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .generic), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .generic), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .generic), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .generic), + + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .image), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .image), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .image), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .image), + + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .video), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .video), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .video), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .video), + + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .audio), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .audio), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .audio), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .audio), + + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .file), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .file), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .file), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .file), + + UsageCalculationTag(connection: .cellular, direction: .incoming, category: .call), + UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .call), + UsageCalculationTag(connection: .wifi, direction: .incoming, category: .call), + UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .call) + ] + + var keys: [NSNumber] = rawKeys.map { $0.key as NSNumber } + + var resetKeys: [NSNumber] = [] + var resetAddKeys: [NSNumber: NSNumber] = [:] + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + if reset.contains(.wifi) { + resetKeys = rawKeys.filter({ $0.connection == .wifi }).map({ $0.key as NSNumber }) + resetAddKeys[UsageCalculationResetKey.wifi.rawValue as NSNumber] = Int64(timestamp) as NSNumber + } + if reset.contains(.cellular) { + resetKeys = rawKeys.filter({ $0.connection == .cellular }).map({ $0.key as NSNumber }) + resetAddKeys[UsageCalculationResetKey.cellular.rawValue as NSNumber] = Int64(timestamp) as NSNumber + } + if !resetKeys.isEmpty { + manager.resetKeys(resetKeys, setKeys: resetAddKeys, completion: {}) + } + keys.append(UsageCalculationResetKey.cellular.rawValue as NSNumber) + keys.append(UsageCalculationResetKey.wifi.rawValue as NSNumber) + + let disposable = manager.currentStats(forKeys: keys).start(next: { next in + var dict: [Int32: Int64] = [:] + for key in keys { + dict[key.int32Value] = 0 + } + (next as! NSDictionary).enumerateKeysAndObjects({ key, value, _ in + dict[(key as! NSNumber).int32Value] = (value as! NSNumber).int64Value + }) + subscriber.putNext(NetworkUsageStats( + generic: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .generic).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .generic).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .generic).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .generic).key]!)), + image: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .image).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .image).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .image).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .image).key]!)), + video: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .video).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .video).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .video).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .video).key]!)), + audio: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .audio).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .audio).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .audio).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .audio).key]!)), + file: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .file).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .file).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .file).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .file).key]!)), + call: NetworkUsageStatsConnectionsEntry( + cellular: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .cellular, direction: .incoming, category: .call).key]!, + outgoing: dict[UsageCalculationTag(connection: .cellular, direction: .outgoing, category: .call).key]!), + wifi: NetworkUsageStatsDirectionsEntry( + incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .call).key]!, + outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .call).key]!)), + resetWifiTimestamp: Int32(dict[UsageCalculationResetKey.wifi.rawValue]!), + resetCellularTimestamp: Int32(dict[UsageCalculationResetKey.cellular.rawValue]!) + )) + })! + return ActionDisposable { + disposable.dispose() + } + }) |> then(Signal.complete() |> delay(5.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} + +public struct NetworkInitializationArguments { + public let apiId: Int32 + public let languagesCategory: String + public let appVersion: String + public let voipMaxLayer: Int32 + public let appData: Data? + + public init(apiId: Int32, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, appData: Data?) { + self.apiId = apiId + self.languagesCategory = languagesCategory + self.appVersion = appVersion + self.voipMaxLayer = voipMaxLayer + self.appData = appData + } +} + +func initializedNetwork(arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal { + return Signal { subscriber in + Queue.concurrentDefaultQueue().async { + let _ = registeredLoggingFunctions + + let serialization = Serialization() + + var apiEnvironment = MTApiEnvironment() + + if let appData = arguments.appData { + if let jsonData = JSON(data: appData) { + if let value = apiJson(jsonData) { + let buffer = Buffer() + value.serialize(buffer, true) + apiEnvironment = apiEnvironment.withUpdatedSystemCode(buffer.makeData()) + } + } + } + + apiEnvironment.apiId = arguments.apiId + apiEnvironment.langPack = arguments.languagesCategory + apiEnvironment.layer = NSNumber(value: Int(serialization.currentLayer())) + apiEnvironment.disableUpdates = supplementary + apiEnvironment = apiEnvironment.withUpdatedLangPackCode(languageCode ?? "en") + + if let effectiveActiveServer = proxySettings?.effectiveActiveServer { + apiEnvironment = apiEnvironment.withUpdatedSocksProxySettings(effectiveActiveServer.mtProxySettings) + } + + apiEnvironment = apiEnvironment.withUpdatedNetworkSettings((networkSettings ?? NetworkSettings.defaultSettings).mtNetworkSettings) + + let context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: false)! + + let seedAddressList: [Int: [String]] + + if testingEnvironment { + seedAddressList = [ + 1: ["149.154.175.10"], + 2: ["149.154.167.40"] + ] + } else { + seedAddressList = [ + 1: ["149.154.175.50", "2001:b28:f23d:f001::a"], + 2: ["149.154.167.50", "2001:67c:4e8:f002::a"], + 3: ["149.154.175.100", "2001:b28:f23d:f003::a"], + 4: ["149.154.167.91", "2001:67c:4e8:f004::a"], + 5: ["149.154.171.5", "2001:b28:f23f:f005::a"] + ] + } + + for (id, ips) in seedAddressList { + context.setSeedAddressSetForDatacenterWithId(id, seedAddressSet: MTDatacenterAddressSet(addressList: ips.map { MTDatacenterAddress(ip: $0, port: 443, preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: nil) })) + } + + context.keychain = keychain + context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: nil, phoneNumber: phoneNumber)) + + #if DEBUG + //let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: nil, phoneNumber: phoneNumber).start(next: nil) + #endif + + let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil))! + mtProto.useTempAuthKeys = context.useTempAuthKeys + mtProto.checkForProxyConnectionIssues = true + + let connectionStatus = Promise(.waitingForNetwork) + + let requestService = MTRequestMessageService(context: context)! + let connectionStatusDelegate = MTProtoConnectionStatusDelegate() + connectionStatusDelegate.action = { [weak connectionStatus] info in + if info.flags.contains(.Connected) { + if !info.flags.intersection([.UpdatingConnectionContext, .PerformingServiceTasks]).isEmpty { + connectionStatus?.set(.single(.updating(proxyAddress: info.proxyAddress))) + } else { + connectionStatus?.set(.single(.online(proxyAddress: info.proxyAddress))) + } + } else { + if !info.flags.contains(.NetworkAvailable) { + connectionStatus?.set(.single(ConnectionStatus.waitingForNetwork)) + } else if !info.flags.contains(.Connected) { + connectionStatus?.set(.single(.connecting(proxyAddress: info.proxyAddress, proxyHasConnectionIssues: info.flags.contains(.ProxyHasConnectionIssues)))) + } else if !info.flags.intersection([.UpdatingConnectionContext, .PerformingServiceTasks]).isEmpty { + connectionStatus?.set(.single(.updating(proxyAddress: info.proxyAddress))) + } else { + connectionStatus?.set(.single(.online(proxyAddress: info.proxyAddress))) + } + } + } + mtProto.delegate = connectionStatusDelegate + mtProto.add(requestService) + + subscriber.putNext(Network(queue: Queue(), datacenterId: datacenterId, context: context, mtProto: mtProto, requestService: requestService, connectionStatusDelegate: connectionStatusDelegate, _connectionStatus: connectionStatus, basePath: basePath)) + subscriber.putCompletion() + } + + return EmptyDisposable + } +} + +private final class NetworkHelper: NSObject, MTContextChangeListener { + private let requestPublicKeys: (Int) -> Signal + private let isContextNetworkAccessAllowedImpl: () -> Signal + + private let contextProxyIdUpdated: (NetworkContextProxyId?) -> Void + + init(requestPublicKeys: @escaping (Int) -> Signal, isContextNetworkAccessAllowed: @escaping () -> Signal, contextProxyIdUpdated: @escaping (NetworkContextProxyId?) -> Void) { + self.requestPublicKeys = requestPublicKeys + self.isContextNetworkAccessAllowedImpl = isContextNetworkAccessAllowed + self.contextProxyIdUpdated = contextProxyIdUpdated + } + + func fetchContextDatacenterPublicKeys(_ context: MTContext!, datacenterId: Int) -> MTSignal! { + return MTSignal { subscriber in + let disposable = self.requestPublicKeys(datacenterId).start(next: { next in + subscriber?.putNext(next) + subscriber?.putCompletion() + }) + + return MTBlockDisposable(block: { + disposable.dispose() + }) + } + } + + func isContextNetworkAccessAllowed(_ context: MTContext!) -> MTSignal! { + return MTSignal { subscriber in + let disposable = self.isContextNetworkAccessAllowedImpl().start(next: { next in + subscriber?.putNext(next as NSNumber) + subscriber?.putCompletion() + }) + + return MTBlockDisposable(block: { + disposable.dispose() + }) + } + } + + func contextApiEnvironmentUpdated(_ context: MTContext!, apiEnvironment: MTApiEnvironment!) { + let settings: MTSocksProxySettings? = apiEnvironment.socksProxySettings + self.contextProxyIdUpdated(settings.flatMap(NetworkContextProxyId.init(settings:))) + } +} + +struct NetworkContextProxyId: Equatable { + private let ip: String + private let port: Int + private let secret: Data +} + +private extension NetworkContextProxyId { + init?(settings: MTSocksProxySettings) { + if let secret = settings.secret, !secret.isEmpty { + self.init(ip: settings.ip, port: Int(settings.port), secret: secret) + } else { + return nil + } + } +} + +public struct NetworkRequestAdditionalInfo: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let acknowledgement = NetworkRequestAdditionalInfo(rawValue: 1 << 0) + public static let progress = NetworkRequestAdditionalInfo(rawValue: 1 << 1) +} + +public enum NetworkRequestResult { + case result(T) + case acknowledged + case progress(Float, Int32) +} + +public final class Network: NSObject, MTRequestMessageServiceDelegate { + private let queue: Queue + public let datacenterId: Int + public let context: MTContext + let mtProto: MTProto + let requestService: MTRequestMessageService + let basePath: String + private let connectionStatusDelegate: MTProtoConnectionStatusDelegate + + private var _multiplexedRequestManager: MultiplexedRequestManager? + var multiplexedRequestManager: MultiplexedRequestManager { + return self._multiplexedRequestManager! + } + + private let _contextProxyId: ValuePromise + var contextProxyId: Signal { + return self._contextProxyId.get() + } + + private let _connectionStatus: Promise + public var connectionStatus: Signal { + return self._connectionStatus.get() |> distinctUntilChanged + } + + public func dropConnectionStatus() { + _connectionStatus.set(.single(.waitingForNetwork)) + } + + public let shouldKeepConnection = Promise(false) + private let shouldKeepConnectionDisposable = MetaDisposable() + + public let shouldExplicitelyKeepWorkerConnections = Promise(false) + public let shouldKeepBackgroundDownloadConnections = Promise(false) + + public var mockConnectionStatus: ConnectionStatus? { + didSet { + if let mockConnectionStatus = self.mockConnectionStatus { + self._connectionStatus.set(.single(mockConnectionStatus)) + } + } + } + + var loggedOut: (() -> Void)? + var didReceiveSoftAuthResetError: (() -> Void)? + + override public var description: String { + return "Network context: \(self.context)" + } + + fileprivate init(queue: Queue, datacenterId: Int, context: MTContext, mtProto: MTProto, requestService: MTRequestMessageService, connectionStatusDelegate: MTProtoConnectionStatusDelegate, _connectionStatus: Promise, basePath: String) { + self.queue = queue + self.datacenterId = datacenterId + self.context = context + self._contextProxyId = ValuePromise((context.apiEnvironment.socksProxySettings as MTSocksProxySettings?).flatMap(NetworkContextProxyId.init(settings:)), ignoreRepeated: true) + self.mtProto = mtProto + self.requestService = requestService + self.connectionStatusDelegate = connectionStatusDelegate + self._connectionStatus = _connectionStatus + self.basePath = basePath + + super.init() + + self.requestService.didReceiveSoftAuthResetError = { [weak self] in + self?.didReceiveSoftAuthResetError?() + } + + let _contextProxyId = self._contextProxyId + context.add(NetworkHelper(requestPublicKeys: { [weak self] id in + if let strongSelf = self { + return strongSelf.request(Api.functions.help.getCdnConfig()) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> NSArray in + let array = NSMutableArray() + if let result = result { + switch result { + case let .cdnConfig(publicKeys): + for key in publicKeys { + switch key { + case let .cdnPublicKey(dcId, publicKey): + if id == Int(dcId) { + let dict = NSMutableDictionary() + dict["key"] = publicKey + dict["fingerprint"] = MTRsaFingerprint(publicKey) + array.add(dict) + } + } + } + } + } + return array + } + } else { + return .never() + } + }, isContextNetworkAccessAllowed: { [weak self] in + if let strongSelf = self { + return strongSelf.shouldKeepConnection.get() |> distinctUntilChanged + } else { + return .single(false) + } + }, contextProxyIdUpdated: { value in + _contextProxyId.set(value) + })) + requestService.delegate = self + + self._multiplexedRequestManager = MultiplexedRequestManager(takeWorker: { [weak self] target, tag, continueInBackground in + if let strongSelf = self { + let datacenterId: Int + let isCdn: Bool + let isMedia: Bool = true + switch target { + case let .main(id): + datacenterId = id + isCdn = false + case let .cdn(id): + datacenterId = id + isCdn = true + } + return strongSelf.makeWorker(datacenterId: datacenterId, isCdn: isCdn, isMedia: isMedia, tag: tag, continueInBackground: continueInBackground) + } + return nil + }) + + let shouldKeepConnectionSignal = self.shouldKeepConnection.get() + |> distinctUntilChanged |> deliverOn(queue) + self.shouldKeepConnectionDisposable.set(shouldKeepConnectionSignal.start(next: { [weak self] value in + if let strongSelf = self { + if value { + Logger.shared.log("Network", "Resume network connection") + strongSelf.mtProto.resume() + } else { + Logger.shared.log("Network", "Pause network connection") + strongSelf.mtProto.pause() + } + } + })) + } + + deinit { + self.shouldKeepConnectionDisposable.dispose() + } + + public var globalTime: TimeInterval { + return context.globalTime() + } + + public var currentGlobalTime: Signal { + return Signal { subscriber in + self.context.performBatchUpdates({ + subscriber.putNext(self.context.globalTime()) + subscriber.putCompletion() + }) + return EmptyDisposable + } + } + + public func requestMessageServiceAuthorizationRequired(_ requestMessageService: MTRequestMessageService!) { + Logger.shared.log("Network", "requestMessageServiceAuthorizationRequired") + self.loggedOut?() + } + + func download(datacenterId: Int, isMedia: Bool, isCdn: Bool = false, tag: MediaResourceFetchTag?) -> Signal { + return self.worker(datacenterId: datacenterId, isCdn: isCdn, isMedia: isMedia, tag: tag) + } + + func upload(tag: MediaResourceFetchTag?) -> Signal { + return self.worker(datacenterId: self.datacenterId, isCdn: false, isMedia: false, tag: tag) + } + + func background() -> Signal { + return self.worker(datacenterId: self.datacenterId, isCdn: false, isMedia: false, tag: nil) + } + + private func makeWorker(datacenterId: Int, isCdn: Bool, isMedia: Bool, tag: MediaResourceFetchTag?, continueInBackground: Bool = false) -> Download { + let queue = Queue.mainQueue() + let shouldKeepWorkerConnection: Signal = combineLatest(queue: queue, self.shouldKeepConnection.get(), self.shouldExplicitelyKeepWorkerConnections.get(), self.shouldKeepBackgroundDownloadConnections.get()) + |> map { shouldKeepConnection, shouldExplicitelyKeepWorkerConnections, shouldKeepBackgroundDownloadConnections -> Bool in + return shouldKeepConnection || shouldExplicitelyKeepWorkerConnections || (continueInBackground && shouldKeepBackgroundDownloadConnections) + } + |> distinctUntilChanged + return Download(queue: self.queue, datacenterId: datacenterId, isMedia: isMedia, isCdn: isCdn, context: self.context, masterDatacenterId: self.datacenterId, usageInfo: usageCalculationInfo(basePath: self.basePath, category: (tag as? TelegramMediaResourceFetchTag)?.statsCategory), shouldKeepConnection: shouldKeepWorkerConnection) + } + + private func worker(datacenterId: Int, isCdn: Bool, isMedia: Bool, tag: MediaResourceFetchTag?) -> Signal { + return Signal { [weak self] subscriber in + if let strongSelf = self { + subscriber.putNext(strongSelf.makeWorker(datacenterId: datacenterId, isCdn: isCdn, isMedia: isMedia, tag: tag)) + } + subscriber.putCompletion() + + return ActionDisposable { + + } + } + } + + public func getApproximateRemoteTimestamp() -> Int32 { + return Int32(self.context.globalTime()) + } + + public func mergeBackupDatacenterAddress(datacenterId: Int32, host: String, port: Int32, secret: Data?) { + self.context.performBatchUpdates { + let address = MTDatacenterAddress(ip: host, port: UInt16(port), preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: secret) + self.context.addAddressForDatacenter(withId: Int(datacenterId), address: address) + + /*let currentScheme = self.context.transportSchemeForDatacenter(withId: Int(datacenterId), media: false, isProxy: false) + if let currentScheme = currentScheme, currentScheme.address.isEqual(to: address) { + } else { + let scheme = MTTransportScheme(transport: MTTcpTransport.self, address: address, media: false) + self.context.updateTransportSchemeForDatacenter(withId: Int(datacenterId), transportScheme: scheme, media: false, isProxy: false) + }*/ + + let currentSchemes = self.context.transportSchemesForDatacenter(withId: Int(datacenterId), media: false, enforceMedia: false, isProxy: false) + var found = false + for scheme in currentSchemes { + if scheme.address.isEqual(to: address) { + found = true + break + } + } + if !found { + let scheme = MTTransportScheme(transport: MTTcpTransport.self, address: address, media: false) + self.context.updateTransportSchemeForDatacenter(withId: Int(datacenterId), transportScheme: scheme, media: false, isProxy: false) + } + } + } + + public func requestWithAdditionalInfo(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse), info: NetworkRequestAdditionalInfo, tag: NetworkRequestDependencyTag? = nil, automaticFloodWait: Bool = true) -> Signal, MTRpcError> { + let requestService = self.requestService + return Signal { subscriber in + let request = MTRequest() + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: tag), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in + if let result = data.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.shouldContinueExecutionWithErrorContext = { errorContext in + guard let errorContext = errorContext else { + return true + } + if errorContext.floodWaitSeconds > 0 && !automaticFloodWait { + return false + } + return true + } + + request.acknowledgementReceived = { + if info.contains(.acknowledgement) { + subscriber.putNext(.acknowledged) + } + } + + request.progressUpdated = { progress, packetSize in + if info.contains(.progress) { + subscriber.putNext(.progress(progress, Int32(clamping: packetSize))) + } + } + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + if let result = (boxedResponse as! BoxedMessage).body as? T { + subscriber.putNext(.result(result)) + subscriber.putCompletion() + } + else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + } + } + + if let tag = tag { + request.shouldDependOnRequest = { other in + if let other = other, let metadata = other.metadata as? WrappedRequestMetadata, let otherTag = metadata.tag { + return tag.shouldDependOn(other: otherTag) + } + return false + } + } + + let internalId: Any! = request.internalId + + requestService.add(request) + + return ActionDisposable { [weak requestService] in + requestService?.removeRequest(byInternalId: internalId) + } + } + } + + public func request(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse), tag: NetworkRequestDependencyTag? = nil, automaticFloodWait: Bool = true) -> Signal { + let requestService = self.requestService + return Signal { subscriber in + let request = MTRequest() + + request.setPayload(data.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(data.0), tag: tag), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(data.0)), responseParser: { response in + if let result = data.2.parse(Buffer(data: response)) { + return BoxedMessage(result) + } + return nil + }) + + request.dependsOnPasswordEntry = false + + request.shouldContinueExecutionWithErrorContext = { errorContext in + guard let errorContext = errorContext else { + return true + } + if errorContext.floodWaitSeconds > 0 && !automaticFloodWait { + return false + } + return true + } + + request.completed = { (boxedResponse, timestamp, error) -> () in + if let error = error { + subscriber.putError(error) + } else { + if let result = (boxedResponse as! BoxedMessage).body as? T { + subscriber.putNext(result) + subscriber.putCompletion() + } + else { + subscriber.putError(MTRpcError(errorCode: 500, errorDescription: "TL_VERIFICATION_ERROR")) + } + } + } + + if let tag = tag { + request.shouldDependOnRequest = { other in + if let other = other, let metadata = other.metadata as? WrappedRequestMetadata, let otherTag = metadata.tag { + return tag.shouldDependOn(other: otherTag) + } + return false + } + } + + let internalId: Any! = request.internalId + + requestService.add(request) + + return ActionDisposable { [weak requestService] in + requestService?.removeRequest(byInternalId: internalId) + } + } + } +} + +public func retryRequest(signal: Signal) -> Signal { + return signal |> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) +} + +class Keychain: NSObject, MTKeychain { + let get: (String) -> Data? + let set: (String, Data) -> Void + let remove: (String) -> Void + + init(get: @escaping (String) -> Data?, set: @escaping (String, Data) -> Void, remove: @escaping (String) -> Void) { + self.get = get + self.set = set + self.remove = remove + } + + func setObject(_ object: Any!, forKey aKey: String!, group: String!) { + let data = NSKeyedArchiver.archivedData(withRootObject: object) + self.set(group + ":" + aKey, data) + } + + func object(forKey aKey: String!, group: String!) -> Any! { + if let data = self.get(group + ":" + aKey) { + return NSKeyedUnarchiver.unarchiveObject(with: data as Data) + } + return nil + } + + func removeObject(forKey aKey: String!, group: String!) { + self.remove(group + ":" + aKey) + } + + func dropGroup(_ group: String!) { + + } +} diff --git a/submodules/TelegramCore/TelegramCore/NetworkLogging.h b/submodules/TelegramCore/TelegramCore/NetworkLogging.h new file mode 100644 index 0000000000..170fb90f72 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NetworkLogging.h @@ -0,0 +1,12 @@ +#ifndef Telegram_NetworkLogging_h +#define Telegram_NetworkLogging_h + +#import + +void NetworkRegisterLoggingFunction(); +void NetworkSetLoggingEnabled(bool); + +void setBridgingTraceFunction(void (*)(NSString *, NSString *)); +void setBridgingShortTraceFunction(void (*)(NSString *, NSString *)); + +#endif diff --git a/submodules/TelegramCore/TelegramCore/NetworkLogging.m b/submodules/TelegramCore/TelegramCore/NetworkLogging.m new file mode 100644 index 0000000000..44d1e2ef7e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NetworkLogging.m @@ -0,0 +1,45 @@ +#import "NetworkLogging.h" + +#import + +#ifdef BUCK +# import +#elif TARGET_OS_IOS +# import +#else +# import +#endif + +static void (*bridgingTrace)(NSString *, NSString *); +void setBridgingTraceFunction(void (*f)(NSString *, NSString *)) { + bridgingTrace = f; +} + +static void (*bridgingShortTrace)(NSString *, NSString *); +void setBridgingShortTraceFunction(void (*f)(NSString *, NSString *)) { + bridgingShortTrace = f; +} + +static void TGTelegramLoggingFunction(NSString *format, va_list args) { + if (bridgingTrace) { + bridgingTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); + } +} + +static void TGTelegramShortLoggingFunction(NSString *format, va_list args) { + if (bridgingShortTrace) { + bridgingShortTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); + } +} + +void NetworkRegisterLoggingFunction() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + MTLogSetLoggingFunction(&TGTelegramLoggingFunction); + MTLogSetShortLoggingFunction(&TGTelegramShortLoggingFunction); + }); +} + +void NetworkSetLoggingEnabled(bool value) { + MTLogSetEnabled(value); +} diff --git a/submodules/TelegramCore/TelegramCore/NetworkSettings.swift b/submodules/TelegramCore/TelegramCore/NetworkSettings.swift new file mode 100644 index 0000000000..4c0fdc7389 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NetworkSettings.swift @@ -0,0 +1,82 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct NetworkSettings: PreferencesEntry, Equatable { + public var reducedBackupDiscoveryTimeout: Bool + public internal(set) var applicationUpdateUrlPrefix: String? + + public static var defaultSettings: NetworkSettings { + return NetworkSettings(reducedBackupDiscoveryTimeout: false, applicationUpdateUrlPrefix: nil) + } + + public init(reducedBackupDiscoveryTimeout: Bool, applicationUpdateUrlPrefix: String?) { + self.reducedBackupDiscoveryTimeout = reducedBackupDiscoveryTimeout + self.applicationUpdateUrlPrefix = applicationUpdateUrlPrefix + } + + public init(decoder: PostboxDecoder) { + self.reducedBackupDiscoveryTimeout = decoder.decodeInt32ForKey("reducedBackupDiscoveryTimeout", orElse: 0) != 0 + self.applicationUpdateUrlPrefix = decoder.decodeOptionalStringForKey("applicationUpdateUrlPrefix") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.reducedBackupDiscoveryTimeout ? 1 : 0, forKey: "reducedBackupDiscoveryTimeout") + if let applicationUpdateUrlPrefix = self.applicationUpdateUrlPrefix { + encoder.encodeString(applicationUpdateUrlPrefix, forKey: "applicationUpdateUrlPrefix") + } else { + encoder.encodeNil(forKey: "applicationUpdateUrlPrefix") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? NetworkSettings else { + return false + } + + return self == to + } +} + +public func updateNetworkSettingsInteractively(postbox: Postbox, network: Network, _ f: @escaping (NetworkSettings) -> NetworkSettings) -> Signal { + return postbox.transaction { transaction -> Void in + updateNetworkSettingsInteractively(transaction: transaction, network: network, f) + } +} + +extension NetworkSettings { + var mtNetworkSettings: MTNetworkSettings { + return MTNetworkSettings(reducedBackupDiscoveryTimeout: self.reducedBackupDiscoveryTimeout) + } +} + +public func updateNetworkSettingsInteractively(transaction: Transaction, network: Network, _ f: @escaping (NetworkSettings) -> NetworkSettings) { + var updateNetwork = false + var updatedSettings: NetworkSettings? + transaction.updatePreferencesEntry(key: PreferencesKeys.networkSettings, { current in + let previous = (current as? NetworkSettings) ?? NetworkSettings.defaultSettings + let updated = f(previous) + updatedSettings = updated + if updated.reducedBackupDiscoveryTimeout != previous.reducedBackupDiscoveryTimeout { + updateNetwork = true + } + return updated + }) + + if updateNetwork, let updatedSettings = updatedSettings { + network.context.updateApiEnvironment { current in + return current?.withUpdatedNetworkSettings(updatedSettings.mtNetworkSettings) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/NetworkType.swift b/submodules/TelegramCore/TelegramCore/NetworkType.swift new file mode 100644 index 0000000000..8f7a116f48 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NetworkType.swift @@ -0,0 +1,254 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +#else +import SwiftSignalKit +import CoreTelephony +#endif + +import TelegramCorePrivateModule + +#if os(iOS) +public enum CellularNetworkType { + case unknown + case gprs + case edge + case thirdG + case lte +} + +extension CellularNetworkType { + init(accessTechnology: String) { + switch accessTechnology { + case CTRadioAccessTechnologyGPRS: + self = .gprs + case CTRadioAccessTechnologyEdge, CTRadioAccessTechnologyCDMA1x: + self = .edge + case CTRadioAccessTechnologyLTE: + self = .lte + case CTRadioAccessTechnologyWCDMA, CTRadioAccessTechnologyHSDPA, CTRadioAccessTechnologyHSUPA, CTRadioAccessTechnologyCDMAEVDORev0, CTRadioAccessTechnologyCDMAEVDORevA, CTRadioAccessTechnologyCDMAEVDORevB, CTRadioAccessTechnologyeHRPD: + self = .thirdG + default: + self = .unknown + } + } +} + +#endif + +enum InternalNetworkType: Equatable { + case none + case wifi + case cellular +} + +public enum NetworkType: Equatable { + case none + case wifi +#if os(iOS) + case cellular(CellularNetworkType) +#endif +} + +extension NetworkType { +#if os(iOS) + init(internalType: InternalNetworkType, cellularType: CellularNetworkType) { + switch internalType { + case .none: + self = .none + case .wifi: + self = .wifi + case .cellular: + self = .cellular(cellularType) + } + } +#else + init(internalType: InternalNetworkType) { + switch internalType { + case .none: + self = .none + case .wifi, .cellular: + self = .wifi + } + } +#endif +} + +private final class WrappedReachability: NSObject { + @objc private static func threadImpl() { + while true { + RunLoop.current.run(until: .distantFuture) + } + } + + static let thread: Thread = { + let thread = Thread(target: WrappedReachability.self, selector: #selector(WrappedReachability.threadImpl), object: nil) + thread.start() + return thread + }() + + @objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) { + f() + } + + private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) { + WrappedReachability.perform(#selector(WrappedReachability.dispatchOnThreadImpl(_:)), on: WrappedReachability.thread, with: f, waitUntilDone: false) + } + + private let reachability: Reachability + + let value: ValuePromise + + override init() { + assert(Thread.current === WrappedReachability.thread) + self.reachability = Reachability.forInternetConnection() + let type: InternalNetworkType + switch self.reachability.currentReachabilityStatus() { + case NotReachable: + type = .none + case ReachableViaWiFi: + type = .wifi + case ReachableViaWWAN: + type = .cellular + default: + type = .none + } + self.value = ValuePromise(type) + + super.init() + + self.reachability.reachabilityChanged = { [weak self] status in + WrappedReachability.dispatchOnThread { + guard let strongSelf = self else { + return + } + let internalNetworkType: InternalNetworkType + switch status { + case NotReachable: + internalNetworkType = .none + case ReachableViaWiFi: + internalNetworkType = .wifi + case ReachableViaWWAN: + internalNetworkType = .cellular + default: + internalNetworkType = .none + } + strongSelf.value.set(internalNetworkType) + } + } + self.reachability.startNotifier() + } + + static var valueRef: Unmanaged? + + static func withInstance(_ f: @escaping (WrappedReachability) -> Void) { + WrappedReachability.dispatchOnThread { + if self.valueRef == nil { + self.valueRef = Unmanaged.passRetained(WrappedReachability()) + } + if let valueRef = self.valueRef { + let value = valueRef.takeUnretainedValue() + f(value) + } + } + } +} + +private final class NetworkTypeManagerImpl { + let queue: Queue + let updated: (NetworkType) -> Void + var networkTypeDisposable: Disposable? + var currentNetworkType: InternalNetworkType? + var networkType: NetworkType? + #if os(iOS) + var currentCellularType: CellularNetworkType + var cellularTypeObserver: NSObjectProtocol? + #endif + + init(queue: Queue, updated: @escaping (NetworkType) -> Void) { + self.queue = queue + self.updated = updated + + #if os(iOS) + let telephonyInfo = CTTelephonyNetworkInfo() + let accessTechnology = telephonyInfo.currentRadioAccessTechnology ?? "" + self.currentCellularType = CellularNetworkType(accessTechnology: accessTechnology) + self.cellularTypeObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.CTRadioAccessTechnologyDidChange, object: nil, queue: nil, using: { [weak self] notification in + queue.async { + guard let strongSelf = self else { + return + } + let accessTechnology = telephonyInfo.currentRadioAccessTechnology ?? "" + let cellularType = CellularNetworkType(accessTechnology: accessTechnology) + if strongSelf.currentCellularType != cellularType { + strongSelf.currentCellularType = cellularType + + if let currentNetworkType = strongSelf.currentNetworkType { + let networkType = NetworkType(internalType: currentNetworkType, cellularType: cellularType) + + if strongSelf.networkType != networkType { + strongSelf.networkType = networkType + strongSelf.updated(networkType) + } + } + } + } + }) + #endif + + let networkTypeDisposable = MetaDisposable() + self.networkTypeDisposable = networkTypeDisposable + + WrappedReachability.withInstance({ [weak self] impl in + networkTypeDisposable.set((impl.value.get() + |> deliverOn(queue)).start(next: { networkStatus in + guard let strongSelf = self else { + return + } + if strongSelf.currentNetworkType != networkStatus { + strongSelf.currentNetworkType = networkStatus + + let networkType: NetworkType + #if os(iOS) + networkType = NetworkType(internalType: networkStatus, cellularType: strongSelf.currentCellularType) + #else + networkType = NetworkType(internalType: networkStatus) + #endif + if strongSelf.networkType != networkType { + strongSelf.networkType = networkType + updated(networkType) + } + } + })) + }) + } + + func stop() { + self.networkTypeDisposable?.dispose() + #if os(iOS) + if let observer = self.cellularTypeObserver { + NotificationCenter.default.removeObserver(observer, name: NSNotification.Name.CTRadioAccessTechnologyDidChange, object: nil) + } + #endif + } +} + +func currentNetworkType() -> Signal { + return Signal { subscriber in + let queue = Queue() + let disposable = MetaDisposable() + queue.async { + let impl = QueueLocalObject(queue: queue, generate: { + return NetworkTypeManagerImpl(queue: queue, updated: { value in + subscriber.putNext(value) + }) + }) + disposable.set(ActionDisposable { + impl.with({ impl in + impl.stop() + }) + }) + } + return disposable + } +} diff --git a/submodules/TelegramCore/TelegramCore/NotificationAutolockReportManager.swift b/submodules/TelegramCore/TelegramCore/NotificationAutolockReportManager.swift new file mode 100644 index 0000000000..fe73be5004 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NotificationAutolockReportManager.swift @@ -0,0 +1,92 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +#if os(macOS) +private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else +private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private final class NotificationAutolockReportManagerImpl { + private let queue: Queue + private let network: Network + let isPerformingUpdate = ValuePromise(false, ignoreRepeated: true) + + private var deadlineDisposable: Disposable? + private let currentRequestDisposable = MetaDisposable() + private var onlineTimer: SignalKitTimer? + + init(queue: Queue, deadline: Signal, network: Network) { + self.queue = queue + self.network = network + + self.deadlineDisposable = (deadline + |> distinctUntilChanged + |> deliverOn(self.queue)).start(next: { [weak self] value in + self?.updateDeadline(value) + }) + } + + deinit { + assert(self.queue.isCurrent()) + self.deadlineDisposable?.dispose() + self.currentRequestDisposable.dispose() + self.onlineTimer?.invalidate() + } + + private func updateDeadline(_ deadline: Int32?) { + self.isPerformingUpdate.set(true) + let value: Int32 + if let deadline = deadline { + value = max(0, deadline - Int32(CFAbsoluteTimeGetCurrent())) + } else { + value = -1 + } + self.currentRequestDisposable.set((self.network.request(Api.functions.account.updateDeviceLocked(period: value)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> deliverOn(self.queue)).start(completed: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.isPerformingUpdate.set(false) + })) + } +} + +final class NotificationAutolockReportManager { + private let queue = Queue() + private let impl: QueueLocalObject + + init(deadline: Signal, network: Network) { + let queue = self.queue + self.impl = QueueLocalObject(queue: self.queue, generate: { + return NotificationAutolockReportManagerImpl(queue: queue, deadline: deadline, network: network) + }) + } + + func isPerformingUpdate() -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.isPerformingUpdate.get().start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/NotificationExceptionsList.swift b/submodules/TelegramCore/TelegramCore/NotificationExceptionsList.swift new file mode 100644 index 0000000000..c9ceff6734 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NotificationExceptionsList.swift @@ -0,0 +1,69 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public final class NotificationExceptionsList: Equatable { + public let peers: [PeerId: Peer] + public let settings: [PeerId: TelegramPeerNotificationSettings] + + public init(peers: [PeerId: Peer], settings: [PeerId: TelegramPeerNotificationSettings]) { + self.peers = peers + self.settings = settings + } + + public static func ==(lhs: NotificationExceptionsList, rhs: NotificationExceptionsList) -> Bool { + return lhs === rhs + } +} + +public func notificationExceptionsList(network: Network) -> Signal { + return network.request(Api.functions.account.getNotifyExceptions(flags: 1 << 1, peer: nil)) |> retryRequest |> map { result in + switch result { + case let .updates(updates, users, chats, _, _): + var peers:[PeerId: Peer] = [:] + var settings:[PeerId : TelegramPeerNotificationSettings] = [:] + + for user in users { + let peer = TelegramUser(user: user) + peers[peer.id] = peer + } + for chat in chats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + peers[peer.id] = peer + } + } + + for update in updates { + switch update { + case let .updateNotifySettings(apiPeer, notifySettings): + switch apiPeer { + case let .notifyPeer(notifyPeer): + let peerId: PeerId + switch notifyPeer { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + settings[peerId] = TelegramPeerNotificationSettings(apiSettings: notifySettings) + default: + break + } + default: + break + } + } + + return NotificationExceptionsList(peers: peers, settings: settings) + default: + return NotificationExceptionsList(peers: [:], settings: [:]) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/NotificationInfoMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/NotificationInfoMessageAttribute.swift new file mode 100644 index 0000000000..6be45cb692 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/NotificationInfoMessageAttribute.swift @@ -0,0 +1,38 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct NotificationInfoMessageAttributeFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let muted = NotificationInfoMessageAttributeFlags(rawValue: 1) + public static let personal = NotificationInfoMessageAttributeFlags(rawValue: 2) + +} + +public class NotificationInfoMessageAttribute: MessageAttribute { + public let flags: NotificationInfoMessageAttributeFlags + + public init(flags: NotificationInfoMessageAttributeFlags) { + self.flags = flags + } + + required public init(decoder: PostboxDecoder) { + self.flags = NotificationInfoMessageAttributeFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + } +} diff --git a/submodules/TelegramCore/TelegramCore/OutgoingChatContextResultMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/OutgoingChatContextResultMessageAttribute.swift new file mode 100644 index 0000000000..5ae4a29923 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/OutgoingChatContextResultMessageAttribute.swift @@ -0,0 +1,30 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class OutgoingChatContextResultMessageAttribute: MessageAttribute { + public let queryId: Int64 + public let id: String + public let hideVia: Bool + + init(queryId: Int64, id: String, hideVia: Bool) { + self.queryId = queryId + self.id = id + self.hideVia = hideVia + } + + required public init(decoder: PostboxDecoder) { + self.queryId = decoder.decodeInt64ForKey("q", orElse: 0) + self.id = decoder.decodeStringForKey("i", orElse: "") + self.hideVia = decoder.decodeBoolForKey("v", orElse: false) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.queryId, forKey: "q") + encoder.encodeString(self.id, forKey: "i") + encoder.encodeBool(self.hideVia, forKey: "v") + } +} diff --git a/submodules/TelegramCore/TelegramCore/OutgoingContentInfoMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/OutgoingContentInfoMessageAttribute.swift new file mode 100644 index 0000000000..75be97b25a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/OutgoingContentInfoMessageAttribute.swift @@ -0,0 +1,40 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct OutgoingContentInfoFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let disableLinkPreviews = OutgoingContentInfoFlags(rawValue: 1 << 0) +} + +public class OutgoingContentInfoMessageAttribute: MessageAttribute { + public let flags: OutgoingContentInfoFlags + + public init(flags: OutgoingContentInfoFlags) { + self.flags = flags + } + + required public init(decoder: PostboxDecoder) { + self.flags = OutgoingContentInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + } + + public func withUpdatedFlags(_ flags: OutgoingContentInfoFlags) -> OutgoingContentInfoMessageAttribute { + return OutgoingContentInfoMessageAttribute(flags: flags) + } +} diff --git a/submodules/TelegramCore/TelegramCore/OutgoingMessageInfoAttribute.swift b/submodules/TelegramCore/TelegramCore/OutgoingMessageInfoAttribute.swift new file mode 100644 index 0000000000..123124fc26 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/OutgoingMessageInfoAttribute.swift @@ -0,0 +1,71 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct OutgoingMessageInfoFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static var transformedMedia = OutgoingMessageInfoFlags(rawValue: 1 << 0) +} + +public class OutgoingMessageInfoAttribute: MessageAttribute { + public let uniqueId: Int64 + public let flags: OutgoingMessageInfoFlags + public let acknowledged: Bool + + init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool) { + self.uniqueId = uniqueId + self.flags = flags + self.acknowledged = acknowledged + } + + required public init(decoder: PostboxDecoder) { + self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0) + self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.acknowledged = decoder.decodeInt32ForKey("ack", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.uniqueId, forKey: "u") + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + encoder.encodeInt32(self.acknowledged ? 1 : 0, forKey: "ack") + } + + public func withUpdatedFlags(_ flags: OutgoingMessageInfoFlags) -> OutgoingMessageInfoAttribute { + return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged) + } + + public func withUpdatedAcknowledged(_ acknowledged: Bool) -> OutgoingMessageInfoAttribute { + return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged) + } +} + +public extension Message { + public var isSentOrAcknowledged: Bool { + if self.flags.contains(.Failed) { + return false + } else if self.flags.isSending { + for attribute in self.attributes { + if let attribute = attribute as? OutgoingMessageInfoAttribute { + if attribute.acknowledged { + return true + } + } + } + return false + } else { + return true + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/OutgoingMessageWithChatContextResult.swift b/submodules/TelegramCore/TelegramCore/OutgoingMessageWithChatContextResult.swift new file mode 100644 index 0000000000..480e69bec7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/OutgoingMessageWithChatContextResult.swift @@ -0,0 +1,145 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit + import UIKit +#endif + +private func aspectFitSize(_ size: CGSize, to: CGSize) -> CGSize { + let scale = min(to.width / max(1.0, size.width), to.height / max(1.0, size.height)) + return CGSize(width: floor(size.width * scale), height: floor(size.height * scale)) +} + +public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: ChatContextResultCollection, result: ChatContextResult, hideVia: Bool = false) -> EnqueueMessage? { + var attributes: [MessageAttribute] = [] + attributes.append(OutgoingChatContextResultMessageAttribute(queryId: result.queryId, id: result.id, hideVia: hideVia)) + if !hideVia { + attributes.append(InlineBotMessageAttribute(peerId: results.botId, title: nil)) + } + switch result.message { + case let .auto(caption, entities, replyMarkup): + if let entities = entities { + attributes.append(entities) + } + if let replyMarkup = replyMarkup { + attributes.append(replyMarkup) + } + switch result { + case let .internalReference(_, id, type, title, description, image, file, message): + if type == "game" { + if peerId.namespace == Namespaces.Peer.SecretChat { + let filteredAttributes = attributes.filter { attribute in + if let _ = attribute as? ReplyMarkupMessageAttribute { + return false + } + return true + } + if let media: Media = file ?? image { + return .message(text: caption, attributes: filteredAttributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil) + } else { + return .message(text: caption, attributes: filteredAttributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil) + } + } else { + return .message(text: "", attributes: attributes, mediaReference: .standalone(media: TelegramMediaGame(gameId: 0, accessHash: 0, name: "", title: title ?? "", description: description ?? "", image: image, file: file)), replyToMessageId: nil, localGroupingKey: nil) + } + } else if let file = file, type == "gif" { + return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) + } else if let image = image { + return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: image), replyToMessageId: nil, localGroupingKey: nil) + } else if let file = file { + return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) + } else { + return nil + } + case let .externalReference(_, id, type, title, description, url, content, thumbnail, message): + if type == "photo" { + if let thumbnail = thumbnail { + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + let thumbnailResource = thumbnail.resource + let imageDimensions = thumbnail.dimensions ?? CGSize(width: 128.0, height: 128.0) + let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: [TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: thumbnailResource)], immediateThumbnailData: nil, reference: nil, partialReference: nil) + return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: tmpImage), replyToMessageId: nil, localGroupingKey: nil) + } else { + return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil) + } + } else if type == "document" || type == "gif" || type == "audio" || type == "voice" { + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if let thumbnail = thumbnail { + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + let thumbnailResource = thumbnail.resource + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: thumbnail.dimensions ?? CGSize(width: 128.0, height: 128.0), resource: thumbnailResource)) + } + var fileName = "file" + if let content = content { + var contentUrl: String? + if let resource = content.resource as? HttpReferenceMediaResource { + contentUrl = resource.url + } else if let resource = content.resource as? WebFileReferenceMediaResource { + contentUrl = resource.url + } + if let contentUrl = contentUrl, let url = URL(string: contentUrl) { + if !url.lastPathComponent.isEmpty { + fileName = url.lastPathComponent + } + } + } + + var fileAttributes: [TelegramMediaFileAttribute] = [] + fileAttributes.append(.FileName(fileName: fileName)) + + if type == "gif" { + fileAttributes.append(.Animated) + } + + if let dimensions = content?.dimensions { + fileAttributes.append(.ImageSize(size: dimensions)) + if type == "gif" { + fileAttributes.append(.Video(duration: Int(Int32(content?.duration ?? 0)), size: dimensions, flags: [])) + } + } + + if type == "audio" || type == "voice" { + fileAttributes.append(.Audio(isVoice: type == "voice", duration: Int(Int32(content?.duration ?? 0)), title: title, performer: description, waveform: nil)) + } + + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + + let resource: TelegramMediaResource + if peerId.namespace == Namespaces.Peer.SecretChat, let webResource = content?.resource as? WebFileReferenceMediaResource { + resource = webResource + } else { + resource = EmptyMediaResource() + } + + let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: content?.mimeType ?? "application/binary", size: nil, attributes: fileAttributes) + return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) + } else { + return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil) + } + } + case let .text(text, entities, disableUrlPreview, replyMarkup): + if let entities = entities { + attributes.append(entities) + } + if let replyMarkup = replyMarkup { + attributes.append(replyMarkup) + } + return .message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil) + case let .mapLocation(media, replyMarkup): + if let replyMarkup = replyMarkup { + attributes.append(replyMarkup) + } + return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil) + case let .contact(media, replyMarkup): + if let replyMarkup = replyMarkup { + attributes.append(replyMarkup) + } + return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil) + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerAccessRestrictionInfo.swift b/submodules/TelegramCore/TelegramCore/PeerAccessRestrictionInfo.swift new file mode 100644 index 0000000000..446fa9850b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerAccessRestrictionInfo.swift @@ -0,0 +1,26 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class PeerAccessRestrictionInfo: PostboxCoding, Equatable { + public let reason: String + + init(reason: String) { + self.reason = reason + } + + public init(decoder: PostboxDecoder) { + self.reason = decoder.decodeStringForKey("rsn", orElse: "") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.reason, forKey: "rsn") + } + + public static func ==(lhs: PeerAccessRestrictionInfo, rhs: PeerAccessRestrictionInfo) -> Bool { + return lhs.reason == rhs.reason + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerAdmins.swift b/submodules/TelegramCore/TelegramCore/PeerAdmins.swift new file mode 100644 index 0000000000..cd89a196d2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerAdmins.swift @@ -0,0 +1,280 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum GroupManagementType { + case restrictedToAdmins + case unrestricted +} + +public enum UpdateGroupManagementTypeError { + case generic +} + +public func updateGroupManagementType(account: Account, peerId: PeerId, type: GroupManagementType) -> Signal { + return .complete() + /*return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { + return account.network.request(Api.functions.channels.toggleInvites(channel: inputChannel, enabled: type == .unrestricted ? .boolTrue : .boolFalse)) + |> mapError { _ -> UpdateGroupManagementTypeError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } + } else if let group = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.toggleChatAdmins(chatId: group.id.id, enabled: type == .restrictedToAdmins ? .boolTrue : .boolFalse)) + |> mapError { _ -> UpdateGroupManagementTypeError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } + } else { + return .complete() + } + } else { + return .complete() + } + } + |> introduceError(UpdateGroupManagementTypeError.self) + |> switchToLatest*/ +} + +public enum RemoveGroupAdminError { + case generic +} + +public func removeGroupAdmin(account: Account, peerId: PeerId, adminId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(adminId), let inputUser = apiInputUser(adminPeer) { + if let group = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.editChatAdmin(chatId: group.id.id, userId: inputUser, isAdmin: .boolFalse)) + |> mapError { _ -> RemoveGroupAdminError in return .generic } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedGroupData, let participants = current.participants { + var updatedParticipants = participants.participants + if case .boolTrue = result { + for i in 0 ..< updatedParticipants.count { + if updatedParticipants[i].peerId == adminId { + switch updatedParticipants[i] { + case let .admin(id, invitedBy, invitedAt): + updatedParticipants[i] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt) + default: + break + } + break + } + } + } + return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return current + } + }) + } |> mapError { _ -> RemoveGroupAdminError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> RemoveGroupAdminError in return .generic } + |> switchToLatest +} + +public enum AddGroupAdminError { + case generic + case addMemberError(AddGroupMemberError) +} + +public func addGroupAdmin(account: Account, peerId: PeerId, adminId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(adminId), let inputUser = apiInputUser(adminPeer) { + if let group = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.editChatAdmin(chatId: group.id.id, userId: inputUser, isAdmin: .boolTrue)) + |> mapError { _ -> AddGroupAdminError in return .generic } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedGroupData, let participants = current.participants { + var updatedParticipants = participants.participants + if case .boolTrue = result { + for i in 0 ..< updatedParticipants.count { + if updatedParticipants[i].peerId == adminId { + switch updatedParticipants[i] { + case let .member(id, invitedBy, invitedAt): + updatedParticipants[i] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt) + default: + break + } + break + } + } + } + return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return current + } + }) + } |> mapError { _ -> AddGroupAdminError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> AddGroupAdminError in return .generic } + |> switchToLatest +} + +public enum UpdateChannelAdminRightsError { + case generic + case addMemberError(AddChannelMemberError) +} + +public func fetchChannelParticipant(account: Account, peerId: PeerId, participantId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(participantId), let inputUser = apiInputUser(adminPeer) { + if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { + return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, userId: inputUser)) + |> map { result -> ChannelParticipant? in + switch result { + case let .channelParticipant(participant, _): + return ChannelParticipant(apiParticipant: participant) + } + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + return .single(nil) + } + } else { + return .single(nil) + } + } |> switchToLatest +} + +public func updateChannelAdminRights(account: Account, peerId: PeerId, adminId: PeerId, rights: TelegramChatAdminRights) -> Signal<(ChannelParticipant?, RenderedChannelParticipant), UpdateChannelAdminRightsError> { + return fetchChannelParticipant(account: account, peerId: peerId, participantId: adminId) + |> mapError { error -> UpdateChannelAdminRightsError in + return .generic + } + |> mapToSignal { currentParticipant -> Signal<(ChannelParticipant?, RenderedChannelParticipant), UpdateChannelAdminRightsError> in + return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant), UpdateChannelAdminRightsError> in + if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(adminId), let inputUser = apiInputUser(adminPeer) { + if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { + let updatedParticipant: ChannelParticipant + if let currentParticipant = currentParticipant, case let .member(_, invitedAt, currentAdminInfo, _) = currentParticipant { + let adminInfo: ChannelParticipantAdminInfo? + if !rights.flags.isEmpty { + adminInfo = ChannelParticipantAdminInfo(rights: rights, promotedBy: currentAdminInfo?.promotedBy ?? account.peerId, canBeEditedByAccountPeer: true) + } else { + adminInfo = nil + } + updatedParticipant = ChannelParticipant.member(id: adminId, invitedAt: invitedAt, adminInfo: adminInfo, banInfo: nil) + } else { + let adminInfo: ChannelParticipantAdminInfo? + if !rights.flags.isEmpty { + adminInfo = ChannelParticipantAdminInfo(rights: rights, promotedBy: account.peerId, canBeEditedByAccountPeer: true) + } else { + adminInfo = nil + } + updatedParticipant = ChannelParticipant.member(id: adminId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: adminInfo, banInfo: nil) + } + return account.network.request(Api.functions.channels.editAdmin(channel: inputChannel, userId: inputUser, adminRights: rights.apiAdminRights)) + |> map { [$0] } + |> `catch` { error -> Signal<[Api.Updates], UpdateChannelAdminRightsError> in + if error.errorDescription == "USER_NOT_PARTICIPANT" { + return addChannelMember(account: account, peerId: peerId, memberId: adminId) + |> map { _ -> [Api.Updates] in + return [] + } + |> mapError { error -> UpdateChannelAdminRightsError in + return .addMemberError(error) + } + |> then(account.network.request(Api.functions.channels.editAdmin(channel: inputChannel, userId: inputUser, adminRights: rights.apiAdminRights)) + |> mapError { error -> UpdateChannelAdminRightsError in + return .generic + } + |> map { [$0] }) + } + return .fail(.generic) + } + |> mapToSignal { result -> Signal<(ChannelParticipant?, RenderedChannelParticipant), UpdateChannelAdminRightsError> in + for updates in result { + account.stateManager.addUpdates(updates) + } + return account.postbox.transaction { transaction -> (ChannelParticipant?, RenderedChannelParticipant) in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData, let adminCount = cachedData.participantsSummary.adminCount { + var updatedAdminCount = adminCount + var wasAdmin = false + if let currentParticipant = currentParticipant { + switch currentParticipant { + case .creator: + wasAdmin = true + case let .member(_, _, adminInfo, _): + if let adminInfo = adminInfo, !adminInfo.rights.isEmpty { + wasAdmin = true + } + } + } + if wasAdmin && rights.isEmpty { + updatedAdminCount = max(1, adminCount - 1) + } else if !wasAdmin && !rights.isEmpty { + updatedAdminCount = adminCount + 1 + } + + return cachedData.withUpdatedParticipantsSummary(cachedData.participantsSummary.withUpdatedAdminCount(updatedAdminCount)) + } else { + return cachedData + } + }) + var peers: [PeerId: Peer] = [:] + var presences: [PeerId: PeerPresence] = [:] + peers[adminPeer.id] = adminPeer + if let presence = transaction.getPeerPresence(peerId: adminPeer.id) { + presences[adminPeer.id] = presence + } + if case let .member(_, _, maybeAdminInfo, _) = updatedParticipant, let adminInfo = maybeAdminInfo { + if let peer = transaction.getPeer(adminInfo.promotedBy) { + peers[peer.id] = peer + } + } + return (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: adminPeer, peers: peers, presences: presences)) + } |> mapError { _ -> UpdateChannelAdminRightsError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> UpdateChannelAdminRightsError in return .generic } + |> switchToLatest + } +} + diff --git a/submodules/TelegramCore/TelegramCore/PeerCommands.swift b/submodules/TelegramCore/TelegramCore/PeerCommands.swift new file mode 100644 index 0000000000..2f73efe746 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerCommands.swift @@ -0,0 +1,66 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct PeerCommand: Equatable { + public let peer: Peer + public let command: BotCommand + + public static func ==(lhs: PeerCommand, rhs: PeerCommand) -> Bool { + return lhs.peer.isEqual(rhs.peer) && lhs.command == rhs.command + } +} + +public struct PeerCommands: Equatable { + public let commands: [PeerCommand] + + public static func ==(lhs: PeerCommands, rhs: PeerCommands) -> Bool { + return lhs.commands == rhs.commands + } +} + +public func peerCommands(account: Account, id: PeerId) -> Signal { + return account.postbox.peerView(id: id) |> map { view -> PeerCommands in + if let cachedUserData = view.cachedData as? CachedUserData { + if let botInfo = cachedUserData.botInfo { + if let botPeer = view.peers[id] { + var commands: [PeerCommand] = [] + for command in botInfo.commands { + commands.append(PeerCommand(peer: botPeer, command: command)) + } + return PeerCommands(commands: commands) + } + } + return PeerCommands(commands: []) + } + else if let cachedGroupData = view.cachedData as? CachedGroupData { + var commands: [PeerCommand] = [] + for cachedBotInfo in cachedGroupData.botInfos { + if let botPeer = view.peers[cachedBotInfo.peerId] { + for command in cachedBotInfo.botInfo.commands { + commands.append(PeerCommand(peer: botPeer, command: command)) + } + } + } + return PeerCommands(commands: commands) + } else if let cachedChannelData = view.cachedData as? CachedChannelData { + var commands: [PeerCommand] = [] + for cachedBotInfo in cachedChannelData.botInfos { + if let botPeer = view.peers[cachedBotInfo.peerId] { + for command in cachedBotInfo.botInfo.commands { + commands.append(PeerCommand(peer: botPeer, command: command)) + } + } + } + return PeerCommands(commands: commands) + } else { + return PeerCommands(commands: []) + } + } + |> distinctUntilChanged +} diff --git a/submodules/TelegramCore/TelegramCore/PeerContactSettings.swift b/submodules/TelegramCore/TelegramCore/PeerContactSettings.swift new file mode 100644 index 0000000000..e890899267 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerContactSettings.swift @@ -0,0 +1,41 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct PeerStatusSettings: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let canReport = PeerStatusSettings(rawValue: 1 << 1) + public static let canShareContact = PeerStatusSettings(rawValue: 1 << 2) + public static let canBlock = PeerStatusSettings(rawValue: 1 << 3) + public static let canAddContact = PeerStatusSettings(rawValue: 1 << 4) +} + +extension PeerStatusSettings { + init(apiSettings: Api.PeerSettings) { + switch apiSettings { + case let .peerSettings(flags): + var result = PeerStatusSettings() + if (flags & (1 << 1)) != 0 { + result.insert(.canAddContact) + } + if (flags & (1 << 0)) != 0 { + result.insert(.canReport) + } + if (flags & (1 << 2)) != 0 { + result.insert(.canBlock) + } + if (flags & (1 << 3)) != 0 { + result.insert(.canShareContact) + } + self = result + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerGroupMessageStateVersionAttribute.swift b/submodules/TelegramCore/TelegramCore/PeerGroupMessageStateVersionAttribute.swift new file mode 100644 index 0000000000..35679cf77a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerGroupMessageStateVersionAttribute.swift @@ -0,0 +1,23 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class PeerGroupMessageStateVersionAttribute: MessageAttribute { + public let stateIndex: Int32 + + public init(stateIndex: Int32) { + self.stateIndex = stateIndex + } + + required public init(decoder: PostboxDecoder) { + self.stateIndex = decoder.decodeInt32ForKey("p", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.stateIndex, forKey: "p") + } +} + diff --git a/submodules/TelegramCore/TelegramCore/PeerInputActivity.swift b/submodules/TelegramCore/TelegramCore/PeerInputActivity.swift new file mode 100644 index 0000000000..d5b9adedc9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerInputActivity.swift @@ -0,0 +1,115 @@ +import Foundation + +public enum PeerInputActivity: Comparable { + case typingText + case uploadingFile(progress: Int32) + case recordingVoice + case uploadingPhoto(progress: Int32) + case uploadingVideo(progress: Int32) + case playingGame + case recordingInstantVideo + case uploadingInstantVideo(progress: Int32) + + public static func ==(lhs: PeerInputActivity, rhs: PeerInputActivity) -> Bool { + switch lhs { + case .typingText: + if case .typingText = rhs { + return true + } else { + return false + } + case let .uploadingFile(progress): + if case .uploadingFile(progress) = rhs { + return true + } else { + return false + } + case .recordingVoice: + if case .recordingVoice = rhs { + return true + } else { + return false + } + case .playingGame: + if case .playingGame = rhs { + return true + } else { + return false + } + case .uploadingPhoto(let progress): + if case .uploadingPhoto(progress) = rhs { + return true + } else { + return false + } + case .uploadingVideo(let progress): + if case .uploadingVideo(progress) = rhs { + return true + } else { + return false + } + case .recordingInstantVideo: + if case .recordingInstantVideo = rhs { + return true + } else { + return false + } + case .uploadingInstantVideo(let progress): + if case .uploadingInstantVideo(progress) = rhs { + return true + } else { + return false + } + } + } + + public var key: Int32 { + switch self { + case .typingText: + return 0 + case .uploadingFile: + return 1 + case .recordingVoice: + return 2 + case .uploadingPhoto: + return 3 + case .uploadingVideo: + return 4 + case .recordingInstantVideo: + return 5 + case .uploadingInstantVideo: + return 6 + case .playingGame: + return 7 + } + } + + public static func <(lhs: PeerInputActivity, rhs: PeerInputActivity) -> Bool { + return lhs.key < rhs.key + } +} + +extension PeerInputActivity { + init?(apiType: Api.SendMessageAction) { + switch apiType { + case .sendMessageCancelAction, .sendMessageChooseContactAction, .sendMessageGeoLocationAction, .sendMessageRecordVideoAction: + return nil + case .sendMessageGamePlayAction: + self = .playingGame + case .sendMessageRecordAudioAction, .sendMessageUploadAudioAction: + self = .recordingVoice + case .sendMessageTypingAction: + self = .typingText + case let .sendMessageUploadDocumentAction(progress): + self = .uploadingFile(progress: progress) + case let .sendMessageUploadPhotoAction(progress): + self = .uploadingPhoto(progress: progress) + case let .sendMessageUploadVideoAction(progress): + self = .uploadingVideo(progress: progress) + case .sendMessageRecordRoundAction: + self = .recordingInstantVideo + case let .sendMessageUploadRoundAction(progress): + self = .uploadingInstantVideo(progress: progress) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerInputActivityManager.swift b/submodules/TelegramCore/TelegramCore/PeerInputActivityManager.swift new file mode 100644 index 0000000000..03bec756a0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerInputActivityManager.swift @@ -0,0 +1,412 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +#if os(macOS) + private typealias SignalKitTimer = SwiftSignalKitMac.Timer +#else + private typealias SignalKitTimer = SwiftSignalKit.Timer +#endif + +private struct ActivityRecord { + let peerId: PeerId + let activity: PeerInputActivity + let id: Int32 + let timer: SignalKitTimer + let episodeId: Int32? + let timestamp: Double + let updateId: Int32 +} + +private final class PeerInputActivityContext { + private let queue: Queue + private let notifyEmpty: () -> Void + private let notifyUpdated: () -> Void + + private var nextId: Int32 = 0 + private var activities: [ActivityRecord] = [] + + private let subscribers = Bag<([(PeerId, PeerInputActivityRecord)]) -> Void>() + + private var scheduledUpdateSubscribers = false + + init(queue: Queue, notifyEmpty: @escaping () -> Void, notifyUpdated: @escaping () -> Void) { + self.queue = queue + self.notifyEmpty = notifyEmpty + self.notifyUpdated = notifyUpdated + } + + func addActivity(peerId: PeerId, activity: PeerInputActivity, timeout: Double, episodeId: Int32?, nextUpdateId: inout Int32) { + assert(self.queue.isCurrent()) + + let timestamp = CFAbsoluteTimeGetCurrent() + + var updated = false + var found = false + for i in 0 ..< self.activities.count { + let record = self.activities[i] + if record.peerId == peerId && record.activity.key == activity.key && record.episodeId == episodeId { + found = true + record.timer.invalidate() + var updateId = record.updateId + var recordTimestamp = record.timestamp + if record.activity != activity || record.timestamp + 4.0 < timestamp { + updated = true + updateId = nextUpdateId + recordTimestamp = timestamp + nextUpdateId += 1 + } + let currentId = record.id + let timer = SignalKitTimer(timeout: timeout, repeat: false, completion: { [weak self] in + if let strongSelf = self { + for currentActivity in strongSelf.activities { + if currentActivity.id == currentId { + strongSelf.removeActivity(peerId: currentActivity.peerId, activity: currentActivity.activity, episodeId: currentActivity.episodeId) + } + } + } + }, queue: self.queue) + self.activities[i] = ActivityRecord(peerId: peerId, activity: activity, id: currentId, timer: timer, episodeId: episodeId, timestamp: recordTimestamp, updateId: updateId) + timer.start() + break + } + } + + if !found { + updated = true + let activityId = self.nextId + self.nextId += 1 + let timer = SignalKitTimer(timeout: timeout, repeat: false, completion: { [weak self] in + if let strongSelf = self { + for currentActivity in strongSelf.activities { + if currentActivity.id == activityId { + strongSelf.removeActivity(peerId: currentActivity.peerId, activity: currentActivity.activity, episodeId: currentActivity.episodeId) + } + } + } + }, queue: self.queue) + let updateId = nextUpdateId + nextUpdateId += 1 + self.activities.insert(ActivityRecord(peerId: peerId, activity: activity, id: activityId, timer: timer, episodeId: episodeId, timestamp: timestamp, updateId: updateId), at: 0) + timer.start() + } + + if updated { + self.scheduleUpdateSubscribers() + } + } + + func removeActivity(peerId: PeerId, activity: PeerInputActivity, episodeId: Int32?) { + assert(self.queue.isCurrent()) + + for i in 0 ..< self.activities.count { + let record = self.activities[i] + if record.peerId == peerId && record.activity.key == activity.key && record.episodeId == episodeId { + self.activities.remove(at: i) + record.timer.invalidate() + self.scheduleUpdateSubscribers() + break + } + } + } + + func removeAllActivities(peerId: PeerId) { + assert(self.queue.isCurrent()) + + var updated = false + for i in (0 ..< self.activities.count).reversed() { + let record = self.activities[i] + if record.peerId == peerId { + record.timer.invalidate() + self.activities.remove(at: i) + updated = true + } + } + + if updated { + self.scheduleUpdateSubscribers() + } + } + + func scheduleUpdateSubscribers() { + if !self.scheduledUpdateSubscribers { + self.scheduledUpdateSubscribers = true + + self.queue.async { [weak self] in + self?.updateSubscribers() + } + } + } + + func isEmpty() -> Bool { + return self.activities.isEmpty && self.subscribers.isEmpty + } + + func topActivities() -> [(PeerId, PeerInputActivityRecord)] { + var peerIds = Set() + var result: [(PeerId, PeerInputActivityRecord)] = [] + for record in self.activities { + if !peerIds.contains(record.peerId) { + peerIds.insert(record.peerId) + result.append((record.peerId, PeerInputActivityRecord(activity: record.activity, updateId: record.updateId))) + if result.count == 10 { + break + } + } + } + return result + } + + func updateSubscribers() { + self.scheduledUpdateSubscribers = false + + if self.isEmpty() { + self.notifyEmpty() + } else { + let topActivities = self.topActivities() + for subscriber in self.subscribers.copyItems() { + subscriber(topActivities) + } + + self.notifyUpdated() + } + } + + func addSubscriber(_ subscriber: @escaping ([(PeerId, PeerInputActivityRecord)]) -> Void) -> Int { + return self.subscribers.add(subscriber) + } + + func removeSubscriber(_ index: Int) { + self.subscribers.remove(index) + } +} + +private final class PeerGlobalInputActivityContext { + private let subscribers = Bag<([PeerId: [PeerId: PeerInputActivityRecord]]) -> Void>() + + func addSubscriber(_ subscriber: @escaping ([PeerId: [PeerId: PeerInputActivityRecord]]) -> Void) -> Int { + return self.subscribers.add(subscriber) + } + + func removeSubscriber(_ index: Int) { + self.subscribers.remove(index) + } + + var isEmpty: Bool { + return self.subscribers.isEmpty + } + + func notify(_ activities: [PeerId: [PeerId: PeerInputActivityRecord]]) { + for subscriber in self.subscribers.copyItems() { + subscriber(activities) + } + } +} + +final class PeerInputActivityManager { + private let queue = Queue() + + private var nextEpisodeId: Int32 = 0 + private var nextUpdateId: Int32 = 0 + private var contexts: [PeerId: PeerInputActivityContext] = [:] + private var globalContext: PeerGlobalInputActivityContext? + + func activities(peerId: PeerId) -> Signal<[(PeerId, PeerInputActivityRecord)], NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let context: PeerInputActivityContext + if let currentContext = strongSelf.contexts[peerId] { + context = currentContext + } else { + context = PeerInputActivityContext(queue: queue, notifyEmpty: { + if let strongSelf = self { + strongSelf.contexts.removeValue(forKey: peerId) + + if let globalContext = strongSelf.globalContext { + let activities = strongSelf.collectActivities() + globalContext.notify(activities) + } + } + }, notifyUpdated: { + if let strongSelf = self, let globalContext = strongSelf.globalContext { + let activities = strongSelf.collectActivities() + globalContext.notify(activities) + } + }) + strongSelf.contexts[peerId] = context + } + let index = context.addSubscriber({ next in + subscriber.putNext(next) + }) + subscriber.putNext(context.topActivities()) + disposable.set(ActionDisposable { + queue.async { + if let strongSelf = self { + if let currentContext = strongSelf.contexts[peerId] { + currentContext.removeSubscriber(index) + if currentContext.isEmpty() { + strongSelf.contexts.removeValue(forKey: peerId) + } + } + } + } + }) + } + } + return disposable + } + } + + private func collectActivities() -> [PeerId: [PeerId: PeerInputActivityRecord]] { + assert(self.queue.isCurrent()) + + var dict: [PeerId: [PeerId: PeerInputActivityRecord]] = [:] + for (chatPeerId, context) in self.contexts { + var chatDict: [PeerId: PeerInputActivityRecord] = [:] + for (peerId, activity) in context.topActivities() { + chatDict[peerId] = activity + } + dict[chatPeerId] = chatDict + } + return dict + } + + func allActivities() -> Signal<[PeerId: [PeerId: PeerInputActivityRecord]], NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + let disposable = MetaDisposable() + queue.async { + if let strongSelf = self { + let context: PeerGlobalInputActivityContext + if let current = strongSelf.globalContext { + context = current + } else { + context = PeerGlobalInputActivityContext() + strongSelf.globalContext = context + } + let index = context.addSubscriber({ next in + subscriber.putNext(next) + }) + subscriber.putNext(strongSelf.collectActivities()) + + disposable.set(ActionDisposable { + queue.async { + if let strongSelf = self { + if let currentContext = strongSelf.globalContext { + currentContext.removeSubscriber(index) + if currentContext.isEmpty { + strongSelf.globalContext = nil + } + } + } + } + }) + } + } + return disposable + } + } + + func addActivity(chatPeerId: PeerId, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) { + self.queue.async { + let context: PeerInputActivityContext + if let currentContext = self.contexts[chatPeerId] { + context = currentContext + } else { + context = PeerInputActivityContext(queue: self.queue, notifyEmpty: { [weak self] in + if let strongSelf = self { + strongSelf.contexts.removeValue(forKey: chatPeerId) + + if let globalContext = strongSelf.globalContext { + let activities = strongSelf.collectActivities() + globalContext.notify(activities) + } + } + }, notifyUpdated: { [weak self] in + if let strongSelf = self, let globalContext = strongSelf.globalContext { + let activities = strongSelf.collectActivities() + globalContext.notify(activities) + } + }) + self.contexts[chatPeerId] = context + } + context.addActivity(peerId: peerId, activity: activity, timeout: 8.0, episodeId: episodeId, nextUpdateId: &self.nextUpdateId) + + if let globalContext = self.globalContext { + let activities = self.collectActivities() + globalContext.notify(activities) + } + } + } + + func removeActivity(chatPeerId: PeerId, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) { + self.queue.async { + if let context = self.contexts[chatPeerId] { + context.removeActivity(peerId: peerId, activity: activity, episodeId: episodeId) + + if let globalContext = self.globalContext { + let activities = self.collectActivities() + globalContext.notify(activities) + } + } + } + } + + func removeAllActivities(chatPeerId: PeerId, peerId: PeerId) { + self.queue.async { + if let currentContext = self.contexts[chatPeerId] { + currentContext.removeAllActivities(peerId: peerId) + + if let globalContext = self.globalContext { + let activities = self.collectActivities() + globalContext.notify(activities) + } + } + } + } + + func transaction(_ f: @escaping (PeerInputActivityManager) -> Void) { + self.queue.async { + f(self) + } + } + + func acquireActivity(chatPeerId: PeerId, peerId: PeerId, activity: PeerInputActivity) -> Disposable { + let disposable = MetaDisposable() + let queue = self.queue + queue.async { + let episodeId = self.nextEpisodeId + self.nextEpisodeId += 1 + + let update: () -> Void = { [weak self] in + self?.addActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId) + } + + let timer = SignalKitTimer(timeout: 5.0, repeat: true, completion: { + update() + }, queue: queue) + timer.start() + update() + + disposable.set(ActionDisposable { [weak self] in + queue.async { + timer.invalidate() + guard let strongSelf = self else { + return + } + + strongSelf.removeActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId) + } + }) + } + return disposable + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerLiveLocationsContext.swift b/submodules/TelegramCore/TelegramCore/PeerLiveLocationsContext.swift new file mode 100644 index 0000000000..b97cd7cbd2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerLiveLocationsContext.swift @@ -0,0 +1,36 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func topPeerActiveLiveLocationMessages(viewTracker: AccountViewTracker, accountPeerId: PeerId, peerId: PeerId) -> Signal<(Peer?, [Message]), NoError> { + return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)]) + |> map { (view, _, _) -> (Peer?, [Message]) in + var accountPeer: Peer? + for entry in view.additionalData { + if case let .peer(id, peer) = entry { + accountPeer = peer + break + } + } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + var result: [Message] = [] + for entry in view.entries { + for media in entry.message.media { + if let location = media as? TelegramMediaMap, let liveBroadcastingTimeout = location.liveBroadcastingTimeout { + if entry.message.timestamp + liveBroadcastingTimeout > timestamp { + result.append(entry.message) + } + } else { + assertionFailure() + } + } + } + return (accountPeer, result) + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerParticipants.swift b/submodules/TelegramCore/TelegramCore/PeerParticipants.swift new file mode 100644 index 0000000000..2d1c399859 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerParticipants.swift @@ -0,0 +1,43 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private struct PeerParticipants: Equatable { + let peers: [Peer] + + static func ==(lhs: PeerParticipants, rhs: PeerParticipants) -> Bool { + if lhs.peers.count != rhs.peers.count { + return false + } + for i in 0 ..< lhs.peers.count { + if !lhs.peers[i].isEqual(rhs.peers[i]) { + return false + } + } + return true + } +} + +public func peerParticipants(postbox: Postbox, id: PeerId) -> Signal<[Peer], NoError> { + return postbox.peerView(id: id) |> map { view -> PeerParticipants in + if let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { + var peers: [Peer] = [] + for participant in participants.participants { + if let peer = view.peers[participant.peerId] { + peers.append(peer) + } + } + return PeerParticipants(peers: peers) + } else { + return PeerParticipants(peers: []) + } + } + |> distinctUntilChanged |> map { participants in + return participants.peers + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerPhotoUpdater.swift b/submodules/TelegramCore/TelegramCore/PeerPhotoUpdater.swift new file mode 100644 index 0000000000..6340f347de --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerPhotoUpdater.swift @@ -0,0 +1,255 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import UIKit +#endif + +public enum UpdatePeerPhotoStatus { + case progress(Float) + case complete([TelegramMediaImageRepresentation]) +} + +public enum UploadPeerPhotoError { + case generic +} + +public func updateAccountPhoto(account: Account, resource: MediaResource?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal { + return updatePeerPhoto(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: account.peerId, photo: resource.flatMap({ uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: $0) }), mapResourceToAvatarSizes: mapResourceToAvatarSizes) +} + +public struct UploadedPeerPhotoData { + fileprivate let resource: MediaResource + fileprivate let content: UploadedPeerPhotoDataContent +} + +private enum UploadedPeerPhotoDataContent { + case result(MultipartUploadResult) + case error +} + +public func uploadedPeerPhoto(postbox: Postbox, network: Network, resource: MediaResource) -> Signal { + return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> map { result -> UploadedPeerPhotoData in + return UploadedPeerPhotoData(resource: resource, content: .result(result)) + } + |> `catch` { _ -> Signal in + return .single(UploadedPeerPhotoData(resource: resource, content: .error)) + } +} + +public func updatePeerPhoto(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peerId: PeerId, photo: Signal?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal { + return updatePeerPhotoInternal(postbox: postbox, network: network, stateManager: stateManager, accountPeerId: accountPeerId, peer: postbox.loadedPeerWithId(peerId), photo: photo, mapResourceToAvatarSizes: mapResourceToAvatarSizes) +} + +public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peer: Signal, photo: Signal?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal { + return peer + |> mapError { _ in return .generic } + |> mapToSignal { peer -> Signal in + if let photo = photo { + return photo + |> take(until: { value in + if case let .result(resultData) = value.content, case .inputFile = resultData { + return SignalTakeAction(passthrough: true, complete: true) + } else { + return SignalTakeAction(passthrough: true, complete: false) + } + }) + |> mapError { _ -> UploadPeerPhotoError in return .generic } + |> mapToSignal { result -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in + switch result.content { + case .error: + return .fail(.generic) + case let .result(resultData): + switch resultData { + case let .progress(progress): + return .single((.progress(progress), result.resource)) + case let .inputFile(file): + if peer is TelegramUser { + return network.request(Api.functions.photos.uploadProfilePhoto(file: file)) + |> mapError { _ in return UploadPeerPhotoError.generic } + |> mapToSignal { photo -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in + var representations: [TelegramMediaImageRepresentation] = [] + switch photo { + case let .photo(photo: apiPhoto, users: _): + switch apiPhoto { + case .photoEmpty: + break + case let .photo(_, _, _, _, _, sizes, dcId): + var sizes = sizes + if sizes.count == 3 { + sizes.remove(at: 1) + } + for size in sizes { + switch size { + case let .photoSize(_, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: CloudPeerPhotoSizeMediaResource(datacenterId: dcId, sizeSpec: w <= 200 ? .small : .fullSize, volumeId: volumeId, localId: localId))) + } + default: + break + } + } + + if let resource = result.resource as? LocalFileReferenceMediaResource { + if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) { + for representation in representations { + postbox.mediaBox.storeResourceData(representation.resource.id, data: data) + } + } + } + + } + } + return postbox.transaction { transaction -> (UpdatePeerPhotoStatus, MediaResource?) in + if let peer = transaction.getPeer(peer.id) { + updatePeers(transaction: transaction, peers: [peer], update: { (_, peer) -> Peer? in + if let peer = peer as? TelegramUser { + return peer.withUpdatedPhoto(representations) + } else { + return peer + } + }) + } + return (.complete(representations), result.resource) + + } |> mapError {_ in return UploadPeerPhotoError.generic} + } + } else { + let request: Signal + if let peer = peer as? TelegramGroup { + request = network.request(Api.functions.messages.editChatPhoto(chatId: peer.id.id, photo: .inputChatUploadedPhoto(file: file))) + } else if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) { + request = network.request(Api.functions.channels.editPhoto(channel: inputChannel, photo: .inputChatUploadedPhoto(file: file))) + } else { + assertionFailure() + request = .complete() + } + + return request + |> mapError {_ in return UploadPeerPhotoError.generic} + |> mapToSignal { updates -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in + guard let chat = updates.chats.first, chat.peerId == peer.id, let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) else { + stateManager?.addUpdates(updates) + return .fail(.generic) + } + + return mapResourceToAvatarSizes(result.resource, groupOrChannel.profileImageRepresentations) + |> introduceError(UploadPeerPhotoError.self) + |> mapToSignal { generatedData -> Signal<(UpdatePeerPhotoStatus, MediaResource?), UploadPeerPhotoError> in + stateManager?.addUpdates(updates) + + for (index, data) in generatedData { + if index >= 0 && index < groupOrChannel.profileImageRepresentations.count { + postbox.mediaBox.storeResourceData(groupOrChannel.profileImageRepresentations[index].resource.id, data: data) + } else { + assertionFailure() + } + } + + return postbox.transaction { transaction -> (UpdatePeerPhotoStatus, MediaResource?) in + updatePeers(transaction: transaction, peers: [groupOrChannel], update: { _, updated in + return updated + }) + return (.complete(groupOrChannel.profileImageRepresentations), result.resource) + } + |> mapError { _ in return .generic } + } + } + } + default: + return .fail(.generic) + } + } + } + |> map { result, resource -> UpdatePeerPhotoStatus in + switch result { + case let .complete(representations): + if let resource = resource as? LocalFileReferenceMediaResource { + if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) { + for representation in representations { + postbox.mediaBox.storeResourceData(representation.resource.id, data: data) + } + } + } + default: + break + } + return result + } + } else { + if let _ = peer as? TelegramUser { + return network.request(Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty)) + |> `catch` { _ -> Signal in + return .fail(.generic) + } + |> mapToSignal { _ -> Signal in + return .single(.complete([])) + } + } else { + let request: Signal + if let peer = peer as? TelegramGroup { + request = network.request(Api.functions.messages.editChatPhoto(chatId: peer.id.id, photo: .inputChatPhotoEmpty)) + } else if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) { + request = network.request(Api.functions.channels.editPhoto(channel: inputChannel, photo: .inputChatPhotoEmpty)) + } else { + assertionFailure() + request = .complete() + } + + return request + |> mapError {_ in return UploadPeerPhotoError.generic} + |> mapToSignal { updates -> Signal in + stateManager?.addUpdates(updates) + for chat in updates.chats { + if chat.peerId == peer.id { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + return postbox.transaction { transaction -> UpdatePeerPhotoStatus in + updatePeers(transaction: transaction, peers: [groupOrChannel], update: { _, updated in + return updated + }) + return .complete(groupOrChannel.profileImageRepresentations) + } + |> mapError { _ in return .generic } + } + } + } + + return .fail(.generic) + } + } + } + } +} + +public func removeAccountPhoto(network: Network, reference: TelegramMediaImageReference?) -> Signal { + if let reference = reference { + switch reference { + case let .cloud(imageId, accessHash, fileReference): + if let fileReference = fileReference { + return network.request(Api.functions.photos.deletePhotos(id: [.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))])) + |> `catch` { _ -> Signal<[Int64], NoError> in + return .single([]) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } + } else { + let api = Api.functions.photos.updateProfilePhoto(id: Api.InputPhoto.inputPhotoEmpty) + return network.request(api) |> map { _ in } |> retryRequest + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerSpecificStickerPack.swift b/submodules/TelegramCore/TelegramCore/PeerSpecificStickerPack.swift new file mode 100644 index 0000000000..d97a84fffb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerSpecificStickerPack.swift @@ -0,0 +1,52 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private struct WrappedStickerPackCollectionInfo: Equatable { + let info: StickerPackCollectionInfo? + + static func ==(lhs: WrappedStickerPackCollectionInfo, rhs: WrappedStickerPackCollectionInfo) -> Bool { + return lhs.info == rhs.info + } +} + +public struct PeerSpecificStickerPackData { + public let packInfo: (StickerPackCollectionInfo, [ItemCollectionItem])? + public let canSetup: Bool +} + +public func peerSpecificStickerPack(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { + if peerId.namespace == Namespaces.Peer.CloudChannel { + let signal: Signal<(WrappedStickerPackCollectionInfo, Bool), NoError> = postbox.combinedView(keys: [.cachedPeerData(peerId: peerId)]) + |> map { view -> (WrappedStickerPackCollectionInfo, Bool) in + let dataView = view.views[.cachedPeerData(peerId: peerId)] as? CachedPeerDataView + return (WrappedStickerPackCollectionInfo(info: (dataView?.cachedPeerData as? CachedChannelData)?.stickerPack), (dataView?.cachedPeerData as? CachedChannelData)?.flags.contains(.canSetStickerSet) ?? false) + } + |> distinctUntilChanged(isEqual: { lhs, rhs -> Bool in + return lhs.0 == rhs.0 && lhs.1 == rhs.1 + }) + + return signal + |> mapToSignal { info, canInstall -> Signal in + if let info = info.info { + return cachedStickerPack(postbox: postbox, network: network, reference: .id(id: info.id.id, accessHash: info.accessHash), forceRemote: false) + |> map { result -> PeerSpecificStickerPackData in + if case let .result(info, items, _) = result { + return PeerSpecificStickerPackData(packInfo: (info, items), canSetup: canInstall) + } else { + return PeerSpecificStickerPackData(packInfo: nil, canSetup: canInstall) + } + } + } else { + return .single(PeerSpecificStickerPackData(packInfo: nil, canSetup: canInstall)) + } + } + } else { + return .single(PeerSpecificStickerPackData(packInfo: nil, canSetup: false)) + } +} diff --git a/submodules/TelegramCore/TelegramCore/PeerUtils.swift b/submodules/TelegramCore/TelegramCore/PeerUtils.swift new file mode 100644 index 0000000000..2a2e6ed8e7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeerUtils.swift @@ -0,0 +1,239 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public extension Peer { + public var debugDisplayTitle: String { + switch self { + case let user as TelegramUser: + return user.name + case let group as TelegramGroup: + return group.title + case let channel as TelegramChannel: + return channel.title + default: + return "" + } + } + + public var displayTitle: String { + return self.debugDisplayTitle + } + + public var compactDisplayTitle: String { + switch self { + case let user as TelegramUser: + if let firstName = user.firstName { + return firstName + } else if let lastName = user.lastName { + return lastName + } else { + return "" + } + case let group as TelegramGroup: + return group.title + case let channel as TelegramChannel: + return channel.title + default: + return "" + } + } + + public var restrictionText: String? { + switch self { + case let user as TelegramUser: + return user.restrictionInfo?.reason + case let channel as TelegramChannel: + return channel.restrictionInfo?.reason + default: + return nil + } + } + + public var addressName: String? { + switch self { + case let user as TelegramUser: + return user.username + case _ as TelegramGroup: + return nil + case let channel as TelegramChannel: + return channel.username + default: + return nil + } + } + + public var displayLetters: [String] { + switch self { + case let user as TelegramUser: + if let firstName = user.firstName, let lastName = user.lastName, !firstName.isEmpty && !lastName.isEmpty { + return [firstName.substring(to: firstName.index(after: firstName.startIndex)).uppercased(), lastName.substring(to: lastName.index(after: lastName.startIndex)).uppercased()] + } else if let firstName = user.firstName, !firstName.isEmpty { + return [firstName.substring(to: firstName.index(after: firstName.startIndex)).uppercased()] + } else if let lastName = user.lastName, !lastName.isEmpty { + return [lastName.substring(to: lastName.index(after: lastName.startIndex)).uppercased()] + } + + return [] + case let group as TelegramGroup: + if group.title.startIndex != group.title.endIndex { + return [group.title.substring(to: group.title.index(after: group.title.startIndex)).uppercased()] + } else { + return [] + } + case let channel as TelegramChannel: + if channel.title.startIndex != channel.title.endIndex { + return [channel.title.substring(to: channel.title.index(after: channel.title.startIndex)).uppercased()] + } else { + return [] + } + default: + return [] + } + } + + public var profileImageRepresentations: [TelegramMediaImageRepresentation] { + if let user = self as? TelegramUser { + return user.photo + } else if let group = self as? TelegramGroup { + return group.photo + } else if let channel = self as? TelegramChannel { + return channel.photo + } + return [] + } + + public var smallProfileImage: TelegramMediaImageRepresentation? { + return smallestImageRepresentation(self.profileImageRepresentations) + } + + public var largeProfileImage: TelegramMediaImageRepresentation? { + return largestImageRepresentation(self.profileImageRepresentations) + } + + public var isDeleted: Bool { + switch self { + case let user as TelegramUser: + return user.firstName == nil && user.lastName == nil + default: + return false + } + } + + public var isScam: Bool { + switch self { + case let user as TelegramUser: + return user.flags.contains(.isScam) + case let channel as TelegramChannel: + return channel.flags.contains(.isScam) + default: + return false + } + } + + public var isVerified: Bool { + switch self { + case let user as TelegramUser: + return user.flags.contains(.isVerified) + case let channel as TelegramChannel: + return channel.flags.contains(.isVerified) + default: + return false + } + } +} + +public extension PeerId { + public var isGroupOrChannel: Bool { + switch self.namespace { + case Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel: + return true + default: + return false + } + } +} + +public func peerDebugDisplayTitles(_ peerIds: [PeerId], _ dict: SimpleDictionary) -> String { + var peers: [Peer] = [] + for id in peerIds { + if let peer = dict[id] { + peers.append(peer) + } + } + return peerDebugDisplayTitles(peers) +} + +public func peerDebugDisplayTitles(_ peers: [Peer]) -> String { + if peers.count == 0 { + return "" + } else { + var string = "" + var first = true + for peer in peers { + if first { + first = false + } else { + string.append(", ") + } + string.append(peer.debugDisplayTitle) + } + return string + } +} + +public func messageMainPeer(_ message: Message) -> Peer? { + if let peer = message.peers[message.id.peerId] { + if let peer = peer as? TelegramSecretChat { + return message.peers[peer.regularPeerId] + } else { + return peer + } + } else { + return nil + } +} + +public func peerViewMainPeer(_ view: PeerView) -> Peer? { + if let peer = view.peers[view.peerId] { + if let peer = peer as? TelegramSecretChat { + return view.peers[peer.regularPeerId] + } else { + return peer + } + } else { + return nil + } +} + +public extension RenderedPeer { + public convenience init(message: Message) { + var peers = SimpleDictionary() + let peerId = message.id.peerId + if let peer = message.peers[peerId] { + peers[peer.id] = peer + if let peer = peer as? TelegramSecretChat { + if let regularPeer = message.peers[peer.regularPeerId] { + peers[regularPeer.id] = regularPeer + } + } + } + self.init(peerId: message.id.peerId, peers: peers) + } + + public var chatMainPeer: Peer? { + if let peer = self.peers[self.peerId] { + if let peer = peer as? TelegramSecretChat { + return self.peers[peer.regularPeerId] + } else { + return peer + } + } else { + return nil + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/PeersNearby.swift b/submodules/TelegramCore/TelegramCore/PeersNearby.swift new file mode 100644 index 0000000000..86e6639658 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PeersNearby.swift @@ -0,0 +1,46 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public struct PeerNearby { + public let id: PeerId + public let expires: Int32 + public let distance: Int32 +} + +public func peersNearby(network: Network, accountStateManager: AccountStateManager, coordinate: (latitude: Double, longitude: Double), radius: Int32) -> Signal<[PeerNearby], NoError> { + let inputGeoPoint = Api.InputGeoPoint.inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude) + + return network.request(Api.functions.contacts.getLocated(geoPoint: inputGeoPoint, radius: radius)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates in + var peersNearby: [PeerNearby] = [] + if let updates = updates { + switch updates { + case let .updates(updates, _, _, _, _): + for update in updates { + if case let .updateContactLocated(contacts) = update { + for case let .contactLocated(userId, expires, distance) in contacts { + peersNearby.append(PeerNearby(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), expires: expires, distance: distance)) + } + } + } + default: + break + } + + accountStateManager.addUpdates(updates) + } + + return .single(peersNearby) + |> then(accountStateManager.updatedPeersNearby()) + } +} diff --git a/submodules/TelegramCore/TelegramCore/PendingMessageManager.swift b/submodules/TelegramCore/TelegramCore/PendingMessageManager.swift new file mode 100644 index 0000000000..aae25dd82c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PendingMessageManager.swift @@ -0,0 +1,1143 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct PendingMessageStatus: Equatable { + public let isRunning: Bool + public let progress: Float + + public static func ==(lhs: PendingMessageStatus, rhs: PendingMessageStatus) -> Bool { + return lhs.isRunning == rhs.isRunning && lhs.progress.isEqual(to: rhs.progress) + } +} + +private enum PendingMessageState { + case none + case collectingInfo(message: Message) + case waitingForUploadToStart(groupId: Int64?, upload: Signal) + case uploading(groupId: Int64?) + case waitingToBeSent(groupId: Int64?, content: PendingMessageUploadedContentAndReuploadInfo) + case sending(groupId: Int64?) + + var groupId: Int64? { + switch self { + case .none: + return nil + case let .collectingInfo(message): + return message.groupingKey + case let .waitingForUploadToStart(groupId, _): + return groupId + case let .uploading(groupId): + return groupId + case let .waitingToBeSent(groupId, _): + return groupId + case let .sending(groupId): + return groupId + } + } +} + +private final class PendingMessageContext { + var state: PendingMessageState = .none + let uploadDisposable = MetaDisposable() + let sendDisposable = MetaDisposable() + var activityType: PeerInputActivity? = nil + var contentType: PendingMessageUploadedContentType? = nil + let activityDisposable = MetaDisposable() + var status: PendingMessageStatus? + var statusSubscribers = Bag<(PendingMessageStatus?) -> Void>() + var forcedReuploadOnce: Bool = false +} + +public enum PendingMessageFailureReason { + case flood + case publicBan + case mediaRestricted +} + +private func reasonForError(_ error: String) -> PendingMessageFailureReason? { + if error.hasPrefix("PEER_FLOOD") { + return .flood + } else if error.hasPrefix("USER_BANNED_IN_CHANNEL") { + return .publicBan + } else if error.hasPrefix("CHAT_SEND_") && error.hasSuffix("_FORBIDDEN") { + return .mediaRestricted + } else { + return nil + } +} + +private final class PeerPendingMessagesSummaryContext { + var messageDeliveredSubscribers = Bag<() -> Void>() + var messageFailedSubscribers = Bag<(PendingMessageFailureReason) -> Void>() +} + +private enum PendingMessageResult { + case progress(Float) +} + +private func uploadActivityTypeForMessage(_ message: Message) -> PeerInputActivity? { + guard message.forwardInfo == nil else { + return nil + } + for media in message.media { + if let _ = media as? TelegramMediaImage { + return .uploadingPhoto(progress: 0) + } else if let file = media as? TelegramMediaFile { + if file.isInstantVideo { + return .uploadingInstantVideo(progress: 0) + } else if file.isVideo && !file.isAnimated { + return .uploadingVideo(progress: 0) + } else if !file.isSticker && !file.isVoice && !file.isAnimated { + return .uploadingFile(progress: 0) + } + } + } + return nil +} + +private func failMessages(postbox: Postbox, ids: [MessageId]) -> Signal { + let modify = postbox.transaction { transaction -> Void in + for id in ids { + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + } + + return modify +} + +private final class PendingMessageRequestDependencyTag: NetworkRequestDependencyTag { + let messageId: MessageId + + init(messageId: MessageId) { + self.messageId = messageId + } + + func shouldDependOn(other: NetworkRequestDependencyTag) -> Bool { + if let other = other as? PendingMessageRequestDependencyTag, self.messageId.peerId == other.messageId.peerId && self.messageId.namespace == other.messageId.namespace { + return self.messageId.id > other.messageId.id + } + return false + } +} + +public final class PendingMessageManager { + private let network: Network + private let postbox: Postbox + private let accountPeerId: PeerId + private let auxiliaryMethods: AccountAuxiliaryMethods + private let stateManager: AccountStateManager + private let localInputActivityManager: PeerInputActivityManager + private let messageMediaPreuploadManager: MessageMediaPreuploadManager + private let revalidationContext: MediaReferenceRevalidationContext + + private let queue = Queue() + + private let _hasPendingMessages = ValuePromise(false, ignoreRepeated: true) + public var hasPendingMessages: Signal { + return self._hasPendingMessages.get() + } + + private var messageContexts: [MessageId: PendingMessageContext] = [:] + private var pendingMessageIds = Set() + private let beginSendingMessagesDisposables = DisposableSet() + + private var peerSummaryContexts: [PeerId: PeerPendingMessagesSummaryContext] = [:] + + var transformOutgoingMessageMedia: TransformOutgoingMessageMedia? + + init(network: Network, postbox: Postbox, accountPeerId: PeerId, auxiliaryMethods: AccountAuxiliaryMethods, stateManager: AccountStateManager, localInputActivityManager: PeerInputActivityManager, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext) { + self.network = network + self.postbox = postbox + self.accountPeerId = accountPeerId + self.auxiliaryMethods = auxiliaryMethods + self.stateManager = stateManager + self.localInputActivityManager = localInputActivityManager + self.messageMediaPreuploadManager = messageMediaPreuploadManager + self.revalidationContext = revalidationContext + } + + deinit { + self.beginSendingMessagesDisposables.dispose() + } + + func updatePendingMessageIds(_ messageIds: Set) { + self.queue.async { + let addedMessageIds = messageIds.subtracting(self.pendingMessageIds) + let removedMessageIds = self.pendingMessageIds.subtracting(messageIds) + let removedSecretMessageIds = Set(removedMessageIds.filter({ $0.peerId.namespace == Namespaces.Peer.SecretChat })) + + var updateUploadingPeerIds = Set() + var updateUploadingGroupIds = Set() + for id in removedMessageIds { + if let context = self.messageContexts[id] { + if let groupId = context.state.groupId { + updateUploadingGroupIds.insert(groupId) + } + context.state = .none + updateUploadingPeerIds.insert(id.peerId) + context.sendDisposable.dispose() + context.uploadDisposable.dispose() + context.activityDisposable.dispose() + + if context.status != nil { + context.status = nil + for subscriber in context.statusSubscribers.copyItems() { + subscriber(nil) + } + } + + if context.statusSubscribers.isEmpty { + self.messageContexts.removeValue(forKey: id) + } + } + } + + if !addedMessageIds.isEmpty { + self.beginSendingMessages(Array(addedMessageIds).sorted()) + } + + self.pendingMessageIds = messageIds + + for peerId in updateUploadingPeerIds { + self.updateWaitingUploads(peerId: peerId) + } + + for groupId in updateUploadingGroupIds { + self.beginSendingGroupIfPossible(groupId: groupId) + } + + if !removedSecretMessageIds.isEmpty { + let _ = (self.postbox.transaction { transaction -> Set in + var peerIdsWithDeliveredMessages = Set() + for id in removedSecretMessageIds { + if let message = transaction.getMessage(id) { + if message.isSentOrAcknowledged { + peerIdsWithDeliveredMessages.insert(id.peerId) + } + } + } + return peerIdsWithDeliveredMessages + } + |> deliverOn(self.queue)).start(next: { [weak self] peerIdsWithDeliveredMessages in + guard let strongSelf = self else { + return + } + for peerId in peerIdsWithDeliveredMessages { + if let context = strongSelf.peerSummaryContexts[peerId] { + for subscriber in context.messageDeliveredSubscribers.copyItems() { + subscriber() + } + } + } + }) + } + + self._hasPendingMessages.set(!self.pendingMessageIds.isEmpty) + } + } + + public func pendingMessageStatus(_ id: MessageId) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.queue.async { + let messageContext: PendingMessageContext + if let current = self.messageContexts[id] { + messageContext = current + } else { + messageContext = PendingMessageContext() + self.messageContexts[id] = messageContext + } + + let index = messageContext.statusSubscribers.add({ status in + subscriber.putNext(status) + }) + + subscriber.putNext(messageContext.status) + + disposable.set(ActionDisposable { + self.queue.async { + if let current = self.messageContexts[id] { + current.statusSubscribers.remove(index) + if case .none = current.status, current.statusSubscribers.isEmpty { + self.messageContexts.removeValue(forKey: id) + } + } + } + }) + } + + return disposable + } + } + + private func canBeginUploadingMessage(id: MessageId, type: PendingMessageUploadedContentType) -> Bool { + assert(self.queue.isCurrent()) + + if case .text = type { + return true + } + + let messageIdsForPeer: [MessageId] = self.messageContexts.keys.filter({ $0.peerId == id.peerId }).sorted() + for contextId in messageIdsForPeer { + if contextId < id { + let context = self.messageContexts[contextId]! + if case .uploading = context.state { + return false + } + } else { + break + } + } + + return true + } + + private func beginSendingMessages(_ ids: [MessageId]) { + assert(self.queue.isCurrent()) + + for id in ids.sorted() { + let messageContext: PendingMessageContext + if let current = self.messageContexts[id] { + messageContext = current + } else { + messageContext = PendingMessageContext() + self.messageContexts[id] = messageContext + } + + let status = PendingMessageStatus(isRunning: false, progress: 0.0) + if status != messageContext.status { + messageContext.status = status + for subscriber in messageContext.statusSubscribers.copyItems() { + subscriber(status) + } + } + } + + let disposable = MetaDisposable() + let messages = self.postbox.messagesAtIds(ids) + |> deliverOn(self.queue) + |> afterDisposed { [weak self, weak disposable] in + if let strongSelf = self, let strongDisposable = disposable { + strongSelf.beginSendingMessagesDisposables.remove(strongDisposable) + } + } + self.beginSendingMessagesDisposables.add(disposable) + disposable.set(messages.start(next: { [weak self] messages in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + for message in messages.filter({ !$0.flags.contains(.Sending) }).sorted(by: { $0.id < $1.id }) { + guard let messageContext = strongSelf.messageContexts[message.id] else { + continue + } + + messageContext.activityType = uploadActivityTypeForMessage(message) + strongSelf.collectUploadingInfo(messageContext: messageContext, message: message) + } + + for (messageContext, _) in strongSelf.messageContexts.values.compactMap({ messageContext -> (PendingMessageContext, Message)? in + if case let .collectingInfo(message) = messageContext.state { + return (messageContext, message) + } else { + return nil + } + }).sorted(by: { lhs, rhs in + return lhs.1.index < rhs.1.index + }) { + if case let .collectingInfo(message) = messageContext.state { + let (contentUploadSignal, contentType) = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, isGrouped: message.groupingKey != nil, message: message) + messageContext.contentType = contentType + + if strongSelf.canBeginUploadingMessage(id: message.id, type: contentType) { + strongSelf.beginUploadingMessage(messageContext: messageContext, id: message.id, groupId: message.groupingKey, uploadSignal: contentUploadSignal) + } else { + messageContext.state = .waitingForUploadToStart(groupId: message.groupingKey, upload: contentUploadSignal) + } + } + } + } + })) + } + + private func beginSendingMessage(messageContext: PendingMessageContext, messageId: MessageId, groupId: Int64?, content: PendingMessageUploadedContentAndReuploadInfo) { + if let groupId = groupId { + messageContext.state = .waitingToBeSent(groupId: groupId, content: content) + } else { + self.commitSendingSingleMessage(messageContext: messageContext, messageId: messageId, content: content) + } + } + + private func beginSendingGroupIfPossible(groupId: Int64) { + if let data = self.dataForPendingMessageGroup(groupId) { + self.commitSendingMessageGroup(groupId: groupId, messages: data) + } + } + + private func dataForPendingMessageGroup(_ groupId: Int64) -> [(messageContext: PendingMessageContext, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo)]? { + var result: [(messageContext: PendingMessageContext, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo)] = [] + + loop: for (id, context) in self.messageContexts { + switch context.state { + case .none: + continue loop + case let .collectingInfo(message): + if message.groupingKey == groupId { + return nil + } + case let .waitingForUploadToStart(contextGroupId, _): + if contextGroupId == groupId { + return nil + } + case let .uploading(contextGroupId): + if contextGroupId == groupId { + return nil + } + case let .waitingToBeSent(contextGroupId, content): + if contextGroupId == groupId { + result.append((context, id, content)) + } + case let .sending(contextGroupId): + if contextGroupId == groupId { + return nil + } + } + } + + if result.isEmpty { + return nil + } else { + return result + } + } + + private func commitSendingMessageGroup(groupId: Int64, messages: [(messageContext: PendingMessageContext, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo)]) { + for (context, _, _) in messages { + context.state = .sending(groupId: groupId) + } + let sendMessage: Signal = self.sendGroupMessagesContent(network: self.network, postbox: self.postbox, stateManager: self.stateManager, group: messages.map { ($0.1, $0.2) }) + |> map { next -> PendingMessageResult in + return .progress(1.0) + } + messages[0].0.sendDisposable.set((sendMessage + |> deliverOn(self.queue) + |> afterDisposed { [weak self] in + /*if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + for (_, id, _) in messages { + if let current = strongSelf.messageContexts[id] { + current.status = .none + for subscriber in current.statusSubscribers.copyItems() { + subscriber(nil) + } + if current.statusSubscribers.isEmpty { + strongSelf.messageContexts.removeValue(forKey: id) + } + } + } + }*/ + }).start()) + } + + private func commitSendingSingleMessage(messageContext: PendingMessageContext, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo) { + messageContext.state = .sending(groupId: nil) + let sendMessage: Signal = self.sendMessageContent(network: self.network, postbox: self.postbox, stateManager: self.stateManager, messageId: messageId, content: content) + |> map { next -> PendingMessageResult in + return .progress(1.0) + } + messageContext.sendDisposable.set((sendMessage + |> deliverOn(self.queue) + |> afterDisposed { [weak self] in + /*if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + if let current = strongSelf.messageContexts[messageId] { + current.status = .none + for subscriber in current.statusSubscribers.copyItems() { + subscriber(nil) + } + if current.statusSubscribers.isEmpty { + strongSelf.messageContexts.removeValue(forKey: messageId) + } + } + }*/ + }).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[messageId] { + let status = PendingMessageStatus(isRunning: true, progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + } + } + })) + } + + private func collectUploadingInfo(messageContext: PendingMessageContext, message: Message) { + messageContext.state = .collectingInfo(message: message) + } + + private func beginUploadingMessage(messageContext: PendingMessageContext, id: MessageId, groupId: Int64?, uploadSignal: Signal) { + messageContext.state = .uploading(groupId: groupId) + + let status = PendingMessageStatus(isRunning: true, progress: 0.0) + messageContext.status = status + for subscriber in messageContext.statusSubscribers.copyItems() { + subscriber(status) + } + self.addContextActivityIfNeeded(messageContext, peerId: id.peerId) + + let queue = self.queue + + messageContext.uploadDisposable.set((uploadSignal + |> deliverOn(queue) + |> `catch` { [weak self] _ -> Signal in + if let strongSelf = self { + let modify = strongSelf.postbox.transaction { transaction -> Void in + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + return modify + |> mapToSignal { _ in + return .complete() + } + } + return .complete() + }).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[id] { + let status = PendingMessageStatus(isRunning: true, progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + case let .content(content): + if let current = strongSelf.messageContexts[id] { + strongSelf.beginSendingMessage(messageContext: current, messageId: id, groupId: groupId, content: content) + strongSelf.updateWaitingUploads(peerId: id.peerId) + if let groupId = groupId { + strongSelf.beginSendingGroupIfPossible(groupId: groupId) + } + } + } + } + })) + } + + private func addContextActivityIfNeeded(_ context: PendingMessageContext, peerId: PeerId) { + if let activityType = context.activityType { + context.activityDisposable.set(self.localInputActivityManager.acquireActivity(chatPeerId: peerId, peerId: self.accountPeerId, activity: activityType)) + } + } + + private func updateWaitingUploads(peerId: PeerId) { + assert(self.queue.isCurrent()) + + let messageIdsForPeer: [MessageId] = self.messageContexts.keys.filter({ $0.peerId == peerId }).sorted() + loop: for contextId in messageIdsForPeer { + let context = self.messageContexts[contextId]! + if case let .waitingForUploadToStart(groupId, uploadSignal) = context.state { + if self.canBeginUploadingMessage(id: contextId, type: context.contentType ?? .media) { + context.state = .uploading(groupId: groupId) + let status = PendingMessageStatus(isRunning: true, progress: 0.0) + context.status = status + for subscriber in context.statusSubscribers.copyItems() { + subscriber(status) + } + self.addContextActivityIfNeeded(context, peerId: peerId) + context.uploadDisposable.set((uploadSignal + |> deliverOn(self.queue)).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[contextId] { + let status = PendingMessageStatus(isRunning: true, progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + case let .content(content): + if let current = strongSelf.messageContexts[contextId] { + strongSelf.beginSendingMessage(messageContext: current, messageId: contextId, groupId: groupId, content: content) + if let groupId = groupId { + strongSelf.beginSendingGroupIfPossible(groupId: groupId) + } + strongSelf.updateWaitingUploads(peerId: peerId) + } + } + } + })) + } + break loop + } + } + } + + private func sendGroupMessagesContent(network: Network, postbox: Postbox, stateManager: AccountStateManager, group: [(messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo)]) -> Signal { + let queue = self.queue + return postbox.transaction { [weak self] transaction -> Signal in + if group.isEmpty { + return .complete() + } + + let peerId = group[0].messageId.peerId + + var messages: [(Message, PendingMessageUploadedContentAndReuploadInfo)] = [] + for (id, content) in group { + if let message = transaction.getMessage(id) { + messages.append((message, content)) + } else { + return failMessages(postbox: postbox, ids: group.map { $0.0 }) + } + } + + messages.sort { $0.0.index < $1.0.index } + + if peerId.namespace == Namespaces.Peer.SecretChat { + for (message, content) in messages { + PendingMessageManager.sendSecretMessageContent(transaction: transaction, message: message, content: content) + } + + return .complete() + } else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + var isForward = false + var replyMessageId: Int32? + + var flags: Int32 = 0 + + for attribute in messages[0].0.attributes { + if let replyAttribute = attribute as? ReplyMessageAttribute { + replyMessageId = replyAttribute.messageId.id + } else if let _ = attribute as? ForwardSourceInfoAttribute { + isForward = true + } else if let attribute = attribute as? NotificationInfoMessageAttribute { + if attribute.flags.contains(.muted) { + flags |= Int32(1 << 5) + } + } + } + + let sendMessageRequest: Signal + if isForward { + flags |= (1 << 9) + + var forwardIds: [(MessageId, Int64)] = [] + for (message, content) in messages { + var uniqueId: Int64? + inner: for attribute in message.attributes { + if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute { + uniqueId = outgoingInfo.uniqueId + break inner + } + } + + if let uniqueId = uniqueId { + switch content.content { + case let .forward(forwardAttribute): + forwardIds.append((forwardAttribute.messageId, uniqueId)) + default: + assertionFailure() + return .complete() + } + } else { + return .complete() + } + } + let forwardPeerIds = Set(forwardIds.map { $0.0.peerId }) + if forwardPeerIds.count != 1 { + assertionFailure() + sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid forward peer ids")) + } else if let inputSourcePeerId = forwardPeerIds.first, let inputSourcePeer = transaction.getPeer(inputSourcePeerId).flatMap(apiInputPeer) { + let dependencyTag = PendingMessageRequestDependencyTag(messageId: messages[0].0.id) + + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: inputSourcePeer, id: forwardIds.map { $0.0.id }, randomId: forwardIds.map { $0.1 }, toPeer: inputPeer), tag: dependencyTag) + } else { + assertionFailure() + sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid forward source")) + } + } else { + flags |= (1 << 7) + if let _ = replyMessageId { + flags |= Int32(1 << 0) + } + + var singleMedias: [Api.InputSingleMedia] = [] + for (message, content) in messages { + var uniqueId: Int64? + inner: for attribute in message.attributes { + if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute { + uniqueId = outgoingInfo.uniqueId + break inner + } + } + if let uniqueId = uniqueId { + switch content.content { + case let .media(inputMedia, text): + var messageEntities: [Api.MessageEntity]? + for attribute in message.attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + messageEntities = apiTextAttributeEntities(attribute, associatedPeers: message.peers) + } + } + + var singleFlags: Int32 = 0 + if let _ = messageEntities { + singleFlags |= 1 << 0 + } + + singleMedias.append(.inputSingleMedia(flags: singleFlags, media: inputMedia, randomId: uniqueId, message: text, entities: messageEntities)) + default: + return failMessages(postbox: postbox, ids: group.map { $0.0 }) + } + } else { + return failMessages(postbox: postbox, ids: group.map { $0.0 }) + } + } + + sendMessageRequest = network.request(Api.functions.messages.sendMultiMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, multiMedia: singleMedias)) + } + + return sendMessageRequest + |> deliverOn(queue) + |> mapToSignal { result -> Signal in + if let strongSelf = self { + return strongSelf.applySentGroupMessages(postbox: postbox, stateManager: stateManager, messages: messages.map { $0.0 }, result: result) + |> mapError { _ -> MTRpcError in + return MTRpcError(errorCode: 400, errorDescription: "empty") + } + } else { + return .never() + } + } + |> `catch` { error -> Signal in + return deferred { + if let strongSelf = self { + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + var allFoundAndValid = true + for (message, _) in messages { + if let context = strongSelf.messageContexts[message.id] { + if context.forcedReuploadOnce { + allFoundAndValid = false + break + } + } else { + allFoundAndValid = false + break + } + } + + if allFoundAndValid { + for (message, _) in messages { + if let context = strongSelf.messageContexts[message.id] { + context.forcedReuploadOnce = true + } + } + + strongSelf.beginSendingMessages(messages.map({ $0.0.id })) + return .complete() + } + } else if let failureReason = reasonForError(error.errorDescription), let message = messages.first?.0 { + if let context = strongSelf.peerSummaryContexts[message.id.peerId] { + for subscriber in context.messageFailedSubscribers.copyItems() { + subscriber(failureReason) + } + } + } + } + return failMessages(postbox: postbox, ids: group.map { $0.0 }) + } |> runOn(queue) + } + } else { + assertionFailure() + return failMessages(postbox: postbox, ids: group.map { $0.0 }) + } + } + |> switchToLatest + } + + static func sendSecretMessageContent(transaction: Transaction, message: Message, content: PendingMessageUploadedContentAndReuploadInfo) { + var secretFile: SecretChatOutgoingFile? + switch content.content { + case let .secretMedia(file, size, key): + if let fileReference = SecretChatOutgoingFileReference(file) { + secretFile = SecretChatOutgoingFile(reference: fileReference, size: size, key: key) + } + default: + break + } + + var layer: SecretChatLayer? + let state = transaction.getPeerChatState(message.id.peerId) as? SecretChatState + if let state = state { + switch state.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + } + + if let state = state, let layer = layer { + var sentAsAction = false + for media in message.media { + if let media = media as? TelegramMediaAction { + if case let .messageAutoremoveTimeoutUpdated(value) = media.action { + sentAsAction = true + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: message.id.peerId, operation: .setMessageAutoremoveTimeout(layer: layer, actionGloballyUniqueId: message.globallyUniqueId!, timeout: value, messageId: message.id), state: state) + if updatedState != state { + transaction.setPeerChatState(message.id.peerId, state: updatedState) + } + } else if case .historyScreenshot = media.action { + sentAsAction = true + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: message.id.peerId, operation: .screenshotMessages(layer: layer, actionGloballyUniqueId: message.globallyUniqueId!, globallyUniqueIds: [], messageId: message.id), state: state) + if updatedState != state { + transaction.setPeerChatState(message.id.peerId, state: updatedState) + } + } + break + } + } + + if sentAsAction { + transaction.updateMessage(message.id, update: { currentMessage in + var flags = StoreMessageFlags(message.flags) + if !flags.contains(.Failed) { + flags.insert(.Sending) + } + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } else { + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: message.id.peerId, operation: .sendMessage(layer: layer, id: message.id, file: secretFile), state: state) + if updatedState != state { + transaction.setPeerChatState(message.id.peerId, state: updatedState) + } + transaction.updateMessage(message.id, update: { currentMessage in + var flags = StoreMessageFlags(message.flags) + if !flags.contains(.Failed) { + flags.insert(.Sending) + } + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + } else { + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + } + + private func sendMessageContent(network: Network, postbox: Postbox, stateManager: AccountStateManager, messageId: MessageId, content: PendingMessageUploadedContentAndReuploadInfo) -> Signal { + let queue = self.queue + return postbox.transaction { [weak self] transaction -> Signal in + guard let message = transaction.getMessage(messageId) else { + return .complete() + } + + if messageId.peerId.namespace == Namespaces.Peer.SecretChat { + PendingMessageManager.sendSecretMessageContent(transaction: transaction, message: message, content: content) + return .complete() + } else if let peer = transaction.getPeer(messageId.peerId), let inputPeer = apiInputPeer(peer) { + var uniqueId: Int64 = 0 + var forwardSourceInfoAttribute: ForwardSourceInfoAttribute? + var messageEntities: [Api.MessageEntity]? + var replyMessageId: Int32? + + var flags: Int32 = 0 + + flags |= (1 << 7) + + for attribute in message.attributes { + if let replyAttribute = attribute as? ReplyMessageAttribute { + replyMessageId = replyAttribute.messageId.id + } else if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute { + uniqueId = outgoingInfo.uniqueId + } else if let attribute = attribute as? ForwardSourceInfoAttribute { + forwardSourceInfoAttribute = attribute + } else if let attribute = attribute as? TextEntitiesMessageAttribute { + messageEntities = apiTextAttributeEntities(attribute, associatedPeers: message.peers) + } else if let attribute = attribute as? OutgoingContentInfoMessageAttribute { + if attribute.flags.contains(.disableLinkPreviews) { + flags |= Int32(1 << 1) + } + } else if let attribute = attribute as? NotificationInfoMessageAttribute { + if attribute.flags.contains(.muted) { + flags |= Int32(1 << 5) + } + } + } + + if let _ = replyMessageId { + flags |= Int32(1 << 0) + } + if let _ = messageEntities { + flags |= Int32(1 << 3) + } + + let dependencyTag = PendingMessageRequestDependencyTag(messageId: messageId) + + let sendMessageRequest: Signal, MTRpcError> + switch content.content { + case .text: + sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities), info: .acknowledgement, tag: dependencyTag) + case let .media(inputMedia, text): + sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities), tag: dependencyTag) + |> map(NetworkRequestResult.result) + case let .forward(sourceInfo): + if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) { + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: 0, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer), tag: dependencyTag) + |> map(NetworkRequestResult.result) + } else { + sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal")) + } + case let .chatContextResult(chatContextResult): + if chatContextResult.hideVia { + flags |= Int32(1 << 11) + } + sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id)) + |> map(NetworkRequestResult.result) + case .messageScreenshot: + sendMessageRequest = network.request(Api.functions.messages.sendScreenshotNotification(peer: inputPeer, replyToMsgId: replyMessageId ?? 0, randomId: uniqueId)) + |> map(NetworkRequestResult.result) + case .secretMedia: + assertionFailure() + sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal")) + } + + return sendMessageRequest + |> deliverOn(queue) + |> mapToSignal { result -> Signal in + guard let strongSelf = self else { + return .never() + } + switch result { + case .progress: + return .complete() + case .acknowledged: + return strongSelf.applyAcknowledgedMessage(postbox: postbox, message: message) + |> mapError { _ -> MTRpcError in + return MTRpcError(errorCode: 400, errorDescription: "internal") + } + case let .result(result): + return strongSelf.applySentMessage(postbox: postbox, stateManager: stateManager, message: message, result: result) + |> mapError { _ -> MTRpcError in + return MTRpcError(errorCode: 400, errorDescription: "internal") + } + } + } + |> `catch` { error -> Signal in + queue.async { + guard let strongSelf = self, let context = strongSelf.messageContexts[messageId] else { + return + } + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + if !context.forcedReuploadOnce { + context.forcedReuploadOnce = true + strongSelf.beginSendingMessages([messageId]) + return + } + } else if let failureReason = reasonForError(error.errorDescription) { + if let context = strongSelf.peerSummaryContexts[message.id.peerId] { + for subscriber in context.messageFailedSubscribers.copyItems() { + subscriber(failureReason) + } + } + } + let _ = (postbox.transaction { transaction -> Void in + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + }).start() + } + + return .complete() + } + } else { + return postbox.transaction { transaction -> Void in + transaction.updateMessage(message.id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + } + } |> switchToLatest + } + + private func applyAcknowledgedMessage(postbox: Postbox, message: Message) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.updateMessage(message.id, update: { currentMessage in + var attributes = message.attributes + var found = false + for i in 0 ..< attributes.count { + if let attribute = attributes[i] as? OutgoingMessageInfoAttribute { + attributes[i] = attribute.withUpdatedAcknowledged(true) + found = true + break + } + } + + if !found { + return .skip + } + + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + + private func applySentMessage(postbox: Postbox, stateManager: AccountStateManager, message: Message, result: Api.Updates) -> Signal { + return applyUpdateMessage(postbox: postbox, stateManager: stateManager, message: message, result: result) + |> afterDisposed { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + if let context = strongSelf.peerSummaryContexts[message.id.peerId] { + for subscriber in context.messageDeliveredSubscribers.copyItems() { + subscriber() + } + } + } + } + } + } + + private func applySentGroupMessages(postbox: Postbox, stateManager: AccountStateManager, messages: [Message], result: Api.Updates) -> Signal { + return applyUpdateGroupMessages(postbox: postbox, stateManager: stateManager, messages: messages, result: result) + |> afterDisposed { [weak self] in + if let strongSelf = self { + strongSelf.queue.async { + if let peerId = messages.first?.id.peerId, let context = strongSelf.peerSummaryContexts[peerId] { + for subscriber in context.messageDeliveredSubscribers.copyItems() { + subscriber() + } + } + } + } + } + } + + public func deliveredMessageEvents(peerId: PeerId) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.queue.async { + let summaryContext: PeerPendingMessagesSummaryContext + if let current = self.peerSummaryContexts[peerId] { + summaryContext = current + } else { + summaryContext = PeerPendingMessagesSummaryContext() + self.peerSummaryContexts[peerId] = summaryContext + } + + let index = summaryContext.messageDeliveredSubscribers.add({ + subscriber.putNext(true) + }) + + disposable.set(ActionDisposable { + self.queue.async { + if let current = self.peerSummaryContexts[peerId] { + current.messageDeliveredSubscribers.remove(index) + if current.messageDeliveredSubscribers.isEmpty { + self.peerSummaryContexts.removeValue(forKey: peerId) + } + } + } + }) + } + + return disposable + } + } + + public func failedMessageEvents(peerId: PeerId) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.queue.async { + let summaryContext: PeerPendingMessagesSummaryContext + if let current = self.peerSummaryContexts[peerId] { + summaryContext = current + } else { + summaryContext = PeerPendingMessagesSummaryContext() + self.peerSummaryContexts[peerId] = summaryContext + } + + let index = summaryContext.messageFailedSubscribers.add({ reason in + subscriber.putNext(reason) + }) + + disposable.set(ActionDisposable { + self.queue.async { + if let current = self.peerSummaryContexts[peerId] { + current.messageFailedSubscribers.remove(index) + if current.messageFailedSubscribers.isEmpty { + self.peerSummaryContexts.removeValue(forKey: peerId) + } + } + } + }) + } + + return disposable + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/PendingMessageUploadedContent.swift b/submodules/TelegramCore/TelegramCore/PendingMessageUploadedContent.swift new file mode 100644 index 0000000000..efbd5fa8ce --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PendingMessageUploadedContent.swift @@ -0,0 +1,685 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +import TelegramCorePrivateModule + +enum PendingMessageUploadedContent { + case text(String) + case media(Api.InputMedia, String) + case forward(ForwardSourceInfoAttribute) + case chatContextResult(OutgoingChatContextResultMessageAttribute) + case secretMedia(Api.InputEncryptedFile, Int32, SecretFileEncryptionKey) + case messageScreenshot +} + +enum PendingMessageReuploadInfo { + case reuploadFile(FileMediaReference) +} + +struct PendingMessageUploadedContentAndReuploadInfo { + let content: PendingMessageUploadedContent + let reuploadInfo: PendingMessageReuploadInfo? +} + +enum PendingMessageUploadedContentResult { + case progress(Float) + case content(PendingMessageUploadedContentAndReuploadInfo) +} + +enum PendingMessageUploadedContentType { + case none + case text + case media +} + +enum PendingMessageUploadError { + case generic +} + +func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, message: Message) -> (Signal, PendingMessageUploadedContentType) { + return messageContentToUpload(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: message.id.peerId, messageId: message.id, attributes: message.attributes, text: message.text, media: message.media) +} + +func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, messageId: MessageId?, attributes: [MessageAttribute], text: String, media: [Media]) -> (Signal, PendingMessageUploadedContentType) { + var contextResult: OutgoingChatContextResultMessageAttribute? + var autoremoveAttribute: AutoremoveTimeoutMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? OutgoingChatContextResultMessageAttribute { + if peerId.namespace != Namespaces.Peer.SecretChat { + contextResult = attribute + } + } else if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + autoremoveAttribute = attribute + } + } + + var forwardInfo: ForwardSourceInfoAttribute? + for attribute in attributes { + if let attribute = attribute as? ForwardSourceInfoAttribute { + if peerId.namespace != Namespaces.Peer.SecretChat { + forwardInfo = attribute + } + } + } + + if let media = media.first as? TelegramMediaAction, media.action == .historyScreenshot { + return (.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .messageScreenshot, reuploadInfo: nil))), .none) + } else if let forwardInfo = forwardInfo { + return (.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .forward(forwardInfo), reuploadInfo: nil))), .text) + } else if let contextResult = contextResult { + return (.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .chatContextResult(contextResult), reuploadInfo: nil))), .text) + } else if let media = media.first, let mediaResult = mediaContentToUpload(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, media: media, text: text, autoremoveAttribute: autoremoveAttribute, messageId: messageId, attributes: attributes) { + return (mediaResult, .media) + } else { + return (.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil))), .text) + } +} + +func mediaContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, media: Media, text: String, autoremoveAttribute: AutoremoveTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute]) -> Signal? { + if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { + if peerId.namespace == Namespaces.Peer.SecretChat, let resource = largest.resource as? SecretFileMediaResource { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(.inputEncryptedFile(id: resource.fileId, accessHash: resource.accessHash), resource.decryptedSize, resource.key), reuploadInfo: nil))) + } + if peerId.namespace != Namespaces.Peer.SecretChat, let reference = image.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil), text), reuploadInfo: nil))) + } else { + return uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, image: image, messageId: messageId, text: text, attributes: attributes, autoremoveAttribute: autoremoveAttribute) + } + } else if let file = media as? TelegramMediaFile { + if let resource = file.resource as? CloudDocumentMediaResource { + if peerId.namespace == Namespaces.Peer.SecretChat { + return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: true, isGrouped: isGrouped, peerId: peerId, messageId: messageId, text: text, attributes: attributes, file: file) + } else { + if forceReupload { + let mediaReference: AnyMediaReference + if file.isSticker { + mediaReference = .standalone(media: file) + } else { + mediaReference = .savedGif(media: file) + } + return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: mediaReference.resourceReference(file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resource) + |> mapError { _ -> PendingMessageUploadError in + return .generic + } + |> mapToSignal { validatedResource -> Signal in + if let validatedResource = validatedResource.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = validatedResource.fileReference { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: reference)), ttlSeconds: nil), text), reuploadInfo: nil))) + } else { + return .fail(.generic) + } + } + } + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), ttlSeconds: nil), text), reuploadInfo: nil))) + } + } else { + return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, messageId: messageId, text: text, attributes: attributes, file: file) + } + } else if let contact = media as? TelegramMediaContact { + let input = Api.InputMedia.inputMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName, vcard: contact.vCardData ?? "") + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(input, text), reuploadInfo: nil))) + } else if let map = media as? TelegramMediaMap { + let input: Api.InputMedia + if let liveBroadcastingTimeout = map.liveBroadcastingTimeout { + input = .inputMediaGeoLive(flags: 1 << 1, geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude), period: liveBroadcastingTimeout) + } else if let venue = map.venue { + input = .inputMediaVenue(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude), title: venue.title, address: venue.address ?? "", provider: venue.provider ?? "", venueId: venue.id ?? "", venueType: venue.type ?? "") + } else { + input = .inputMediaGeoPoint(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude)) + } + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(input, text), reuploadInfo: nil))) + } else if let poll = media as? TelegramMediaPoll { + if peerId.namespace == Namespaces.Peer.SecretChat { + return .fail(.generic) + } + let inputPoll = Api.InputMedia.inputMediaPoll(poll: Api.Poll.poll(id: 0, flags: 0, question: poll.text, answers: poll.options.map({ $0.apiOption }))) + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil))) + } else { + return nil + } +} + +private enum PredownloadedResource { + case localReference(CachedSentMediaReferenceKey?) + case media(Media) + case none +} + +private func maybePredownloadedImageResource(postbox: Postbox, peerId: PeerId, resource: MediaResource, forceRefresh: Bool) -> Signal { + if peerId.namespace == Namespaces.Peer.SecretChat { + return .single(.none) + } + + return Signal, PendingMessageUploadError> { subscriber in + let data = postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false)).start(next: { data in + if data.complete { + if data.size < 5 * 1024 * 1024, let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: .mappedRead) { + let md5 = IncrementalMD5() + fileData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + var offset = 0 + let bufferSize = 32 * 1024 + + while offset < fileData.count { + let partSize = min(fileData.count - offset, bufferSize) + md5.update(bytes.advanced(by: offset), count: Int32(partSize)) + offset += bufferSize + } + } + + let res = md5.complete() + + let reference: CachedSentMediaReferenceKey = .image(hash: res) + if forceRefresh { + subscriber.putNext(.single(.localReference(reference))) + } else { + subscriber.putNext(cachedSentMediaReference(postbox: postbox, key: reference) + |> mapError { _ -> PendingMessageUploadError in return .generic } |> map { media -> PredownloadedResource in + if let media = media { + return .media(media) + } else { + return .localReference(reference) + } + }) + } + subscriber.putCompletion() + } else { + subscriber.putNext(.single(.localReference(nil))) + subscriber.putCompletion() + } + } + }) + let fetched = postbox.mediaBox.fetchedResource(resource, parameters: nil).start(error: { _ in + subscriber.putError(.generic) + }) + + return ActionDisposable { + data.dispose() + fetched.dispose() + } + } + |> switchToLatest +} + +private func maybePredownloadedFileResource(postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, peerId: PeerId, resource: MediaResource, forceRefresh: Bool) -> Signal { + if peerId.namespace == Namespaces.Peer.SecretChat { + return .single(.none) + } + + return auxiliaryMethods.fetchResourceMediaReferenceHash(resource) + |> mapToSignal { hash -> Signal in + if let hash = hash { + let reference: CachedSentMediaReferenceKey = .file(hash: hash) + if forceRefresh { + return .single(.localReference(reference)) + } + return cachedSentMediaReference(postbox: postbox, key: reference) |> map { media -> PredownloadedResource in + if let media = media { + return .media(media) + } else { + return .localReference(reference) + } + } + } else { + return .single(.localReference(nil)) + } + } + |> mapError { _ -> PendingMessageUploadError in return .generic } +} + +private func maybeCacheUploadedResource(postbox: Postbox, key: CachedSentMediaReferenceKey?, result: PendingMessageUploadedContentResult, media: Media) -> Signal { + if let key = key { + return postbox.transaction { transaction -> PendingMessageUploadedContentResult in + storeCachedSentMediaReference(transaction: transaction, key: key, media: media) + return result + } |> mapError { _ -> PendingMessageUploadError in return .generic } + } else { + return .single(result) + } +} + +private func uploadedMediaImageContent(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, image: TelegramMediaImage, messageId: MessageId?, text: String, attributes: [MessageAttribute], autoremoveAttribute: AutoremoveTimeoutMessageAttribute?) -> Signal { + guard let largestRepresentation = largestImageRepresentation(image.representations) else { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil))) + } + + let predownloadedResource: Signal = maybePredownloadedImageResource(postbox: postbox, peerId: peerId, resource: largestRepresentation.resource, forceRefresh: forceReupload) + return predownloadedResource + |> mapToSignal { result -> Signal in + var referenceKey: CachedSentMediaReferenceKey? + switch result { + case let .media(media): + if !forceReupload, let image = media as? TelegramMediaImage, let reference = image.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference { + var flags: Int32 = 0 + var ttlSeconds: Int32? + if let autoremoveAttribute = autoremoveAttribute { + flags |= 1 << 0 + ttlSeconds = autoremoveAttribute.timeout + } + return .single(.progress(1.0)) + |> then( + .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: ttlSeconds), text), reuploadInfo: nil))) + ) + } + case let .localReference(key): + referenceKey = key + case .none: + referenceKey = nil + } + + var alreadyTransformed = false + for attribute in attributes { + if let attribute = attribute as? OutgoingMessageInfoAttribute { + if attribute.flags.contains(.transformedMedia) { + alreadyTransformed = true + } + } + } + let transform: Signal + if let transformOutgoingMessageMedia = transformOutgoingMessageMedia, let messageId = messageId, !alreadyTransformed { + transform = .single(.pending) + |> then( + transformOutgoingMessageMedia(postbox, network, .standalone(media: image), false) + |> mapToSignal { mediaReference -> Signal in + return postbox.transaction { transaction -> UploadedMediaTransform in + if let media = mediaReference?.media { + if let id = media.id { + let _ = transaction.updateMedia(id, update: media) + transaction.updateMessage(messageId, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: nil) + } + var updatedAttributes = currentMessage.attributes + if let index = updatedAttributes.index(where: { $0 is OutgoingMessageInfoAttribute }){ + let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute + updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) + } else { + updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false)) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + } + return .done(media) + } else { + return .done(image) + } + } + } + ) + } else { + transform = .single(.done(image)) + } + + return transform + |> mapError { _ -> PendingMessageUploadError in + return .generic + } + |> mapToSignal { transformResult -> Signal in + switch transformResult { + case .pending: + return .single(.progress(0.0)) + case let .done(transformedMedia): + let transformedImage = (transformedMedia as? TelegramMediaImage) ?? image + guard let largestRepresentation = largestImageRepresentation(transformedImage.representations) else { + return .fail(.generic) + } + let imageReference: AnyMediaReference + if let partialReference = transformedImage.partialReference { + imageReference = partialReference.mediaReference(transformedImage) + } else { + imageReference = .standalone(media: transformedImage) + } + return multipartUpload(network: network, postbox: postbox, source: .resource(imageReference.resourceReference(largestRepresentation.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { next -> Signal in + switch next { + case let .progress(progress): + return .single(.progress(progress)) + case let .inputFile(file): + var flags: Int32 = 0 + var ttlSeconds: Int32? + if let autoremoveAttribute = autoremoveAttribute { + flags |= 1 << 1 + ttlSeconds = autoremoveAttribute.timeout + } + return postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { inputPeer -> Signal in + if let inputPeer = inputPeer { + if autoremoveAttribute != nil { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil))) + } + + return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds))) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { result -> Signal in + switch result { + case let .messageMediaPhoto(_, photo, _): + if let photo = photo, let mediaImage = telegramMediaImageFromApiPhoto(photo), let reference = mediaImage.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference { + var flags: Int32 = 0 + var ttlSeconds: Int32? + if let autoremoveAttribute = autoremoveAttribute { + flags |= 1 << 0 + ttlSeconds = autoremoveAttribute.timeout + } + return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: ttlSeconds), text), reuploadInfo: nil)), media: mediaImage) + } + default: + break + } + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + case let .inputSecretFile(file, size, key): + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(file, size, key), reuploadInfo: nil))) + } + } + } + } + } +} + +func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaFileAttribute]) -> [Api.DocumentAttribute] { + var attributes: [Api.DocumentAttribute] = [] + for attribute in fileAttributes { + switch attribute { + case .Animated: + attributes.append(.documentAttributeAnimated) + case let .FileName(fileName): + attributes.append(.documentAttributeFilename(fileName: fileName)) + case let .ImageSize(size): + attributes.append(.documentAttributeImageSize(w: Int32(size.width), h: Int32(size.height))) + case let .Sticker(displayText, packReference, maskCoords): + var stickerSet: Api.InputStickerSet = .inputStickerSetEmpty + var flags: Int32 = 0 + if let packReference = packReference { + switch packReference { + case let .id(id, accessHash): + stickerSet = .inputStickerSetID(id: id, accessHash: accessHash) + case let .name(name): + stickerSet = .inputStickerSetShortName(shortName: name) + } + } + var inputMaskCoords: Api.MaskCoords? + if let maskCoords = maskCoords { + flags |= 1 << 0 + inputMaskCoords = .maskCoords(n: maskCoords.n, x: maskCoords.x, y: maskCoords.y, zoom: maskCoords.zoom) + } + attributes.append(.documentAttributeSticker(flags: flags, alt: displayText, stickerset: stickerSet, maskCoords: inputMaskCoords)) + case .HasLinkedStickers: + attributes.append(.documentAttributeHasStickers) + case let .Video(duration, size, videoFlags): + var flags: Int32 = 0 + if videoFlags.contains(.instantRoundVideo) { + flags |= (1 << 0) + } + if videoFlags.contains(.supportsStreaming) { + flags |= (1 << 1) + } + + attributes.append(.documentAttributeVideo(flags: flags, duration: Int32(duration), w: Int32(size.width), h: Int32(size.height))) + case let .Audio(isVoice, duration, title, performer, waveform): + var flags: Int32 = 0 + if isVoice { + flags |= Int32(1 << 10) + } + if let _ = title { + flags |= Int32(1 << 0) + } + if let _ = performer { + flags |= Int32(1 << 1) + } + var waveformBuffer: Buffer? + if let waveform = waveform { + flags |= Int32(1 << 2) + waveformBuffer = Buffer(data: waveform.makeData()) + } + attributes.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) + } + } + return attributes +} + +private enum UploadedMediaTransform { + case pending + case done(Media?) +} + +private enum UploadedMediaThumbnailResult { + case file(Api.InputFile) + case none +} + +private enum UploadedMediaFileAndThumbnail { + case pending + case done(TelegramMediaFile, UploadedMediaThumbnailResult) +} + +private func uploadedThumbnail(network: Network, postbox: Postbox, resourceReference: MediaResourceReference) -> Signal { + return multipartUpload(network: network, postbox: postbox, source: .resource(resourceReference), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { result -> Signal in + switch result { + case .progress: + return .complete() + case let .inputFile(inputFile): + return .single(inputFile) + case .inputSecretFile: + return .single(nil) + } + } +} + +public func statsCategoryForFileWithAttributes(_ attributes: [TelegramMediaFileAttribute]) -> MediaResourceStatsCategory { + for attribute in attributes { + switch attribute { + case .Audio: + return .audio + case .Video: + return .video + default: + break + } + } + return .file +} + +private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, messageId: MessageId?, text: String, attributes: [MessageAttribute], file: TelegramMediaFile) -> Signal { + return maybePredownloadedFileResource(postbox: postbox, auxiliaryMethods: auxiliaryMethods, peerId: peerId, resource: file.resource, forceRefresh: forceReupload) + |> mapToSignal { result -> Signal in + var referenceKey: CachedSentMediaReferenceKey? + switch result { + case let .media(media): + if !forceReupload, let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference { + return .single(.progress(1.0)) + |> then( + .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil), text), reuploadInfo: nil))) + ) + } + case let .localReference(key): + referenceKey = key + case .none: + referenceKey = nil + } + + var hintFileIsLarge = false + var hintSize: Int? + if let size = file.size { + hintSize = size + } else if let resource = file.resource as? LocalFileReferenceMediaResource, let size = resource.size { + hintSize = Int(size) + } + if (file.resource.headerSize != 0 || file.mimeType.hasPrefix("video/mp4")) && !file.isAnimated { + hintFileIsLarge = true + } + let fileReference: AnyMediaReference + if let partialReference = file.partialReference { + fileReference = partialReference.mediaReference(file) + } else { + fileReference = .standalone(media: file) + } + let upload = messageMediaPreuploadManager.upload(network: network, postbox: postbox, source: .resource(fileReference.resourceReference(file.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(file.attributes)), hintFileSize: hintSize, hintFileIsLarge: hintFileIsLarge) + |> mapError { _ -> PendingMessageUploadError in return .generic + } + var alreadyTransformed = false + for attribute in attributes { + if let attribute = attribute as? OutgoingMessageInfoAttribute { + if attribute.flags.contains(.transformedMedia) { + alreadyTransformed = true + } + } + } + + let transform: Signal + if let transformOutgoingMessageMedia = transformOutgoingMessageMedia, let messageId = messageId, !alreadyTransformed { + transform = .single(.pending) + |> then(transformOutgoingMessageMedia(postbox, network, .standalone(media: file), false) + |> mapToSignal { mediaReference -> Signal in + return postbox.transaction { transaction -> UploadedMediaTransform in + if let media = mediaReference?.media { + if let id = media.id { + let _ = transaction.updateMedia(id, update: media) + transaction.updateMessage(messageId, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: nil) + } + var updatedAttributes = currentMessage.attributes + if let index = updatedAttributes.index(where: { $0 is OutgoingMessageInfoAttribute }){ + let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute + updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) + } else { + updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false)) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)) + }) + } + return .done(media) + } else { + return .done(file) + } + } + }) + } else { + transform = .single(.done(file)) + } + + let transformedFileAndThumbnail: Signal = .single(.pending) + |> then(transform + |> mapToSignalPromotingError { media -> Signal in + switch media { + case .pending: + return .single(.pending) + case let .done(media): + if let media = media as? TelegramMediaFile, let smallestThumbnail = smallestImageRepresentation(media.previewRepresentations) { + if peerId.namespace == Namespaces.Peer.SecretChat { + return .single(.done(media, .none)) + } else { + let fileReference: AnyMediaReference + if let partialReference = media.partialReference { + fileReference = partialReference.mediaReference(media) + } else { + fileReference = .standalone(media: media) + } + + return uploadedThumbnail(network: network, postbox: postbox, resourceReference: fileReference.resourceReference(smallestThumbnail.resource)) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> map { result in + if let result = result { + return .done(media, .file(result)) + } else { + return .done(media, .none) + } + } + } + } else { + return .single(.done(file, .none)) + } + } + }) + + return combineLatest(upload, transformedFileAndThumbnail) + |> mapToSignal { content, fileAndThumbnailResult -> Signal in + switch content { + case let .progress(progress): + return .single(.progress(progress)) + case let .inputFile(inputFile): + if case let .done(file, thumbnail) = fileAndThumbnailResult { + var flags: Int32 = 0 + + var thumbnailFile: Api.InputFile? + if case let .file(file) = thumbnail { + thumbnailFile = file + } + + if let _ = thumbnailFile { + flags |= 1 << 2 + } + + var ttlSeconds: Int32? + for attribute in attributes { + if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { + flags |= 1 << 1 + ttlSeconds = attribute.timeout + } + } + + if !file.isAnimated { + flags |= 1 << 3 + } + + + if ttlSeconds != nil { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil))) + } + + if !isGrouped { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil))) + } + + return postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { inputPeer -> Signal in + if let inputPeer = inputPeer { + return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, ttlSeconds: ttlSeconds))) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapToSignal { result -> Signal in + switch result { + case let .messageMediaDocument(_, document, _): + if let document = document, let mediaFile = telegramMediaFileFromApiDocument(document), let resource = mediaFile.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference { + return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil), text), reuploadInfo: nil)), media: mediaFile) + } + default: + break + } + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + } else { + return .complete() + } + case let .inputSecretFile(file, size, key): + if case .done = fileAndThumbnailResult { + return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(file, size, key), reuploadInfo: nil))) + } else { + return .complete() + } + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/PhoneNumber.swift b/submodules/TelegramCore/TelegramCore/PhoneNumber.swift new file mode 100644 index 0000000000..ddc3d906a2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PhoneNumber.swift @@ -0,0 +1,14 @@ + +public struct PhoneNumberWithLabel: Equatable { + public let label: String + public let number: String + + public init(label: String, number: String) { + self.label = label + self.number = number + } + + public static func ==(lhs: PhoneNumberWithLabel, rhs: PhoneNumberWithLabel) -> Bool { + return lhs.label == rhs.label && lhs.number == rhs.number + } +} diff --git a/submodules/TelegramCore/TelegramCore/PhoneNumbers.swift b/submodules/TelegramCore/TelegramCore/PhoneNumbers.swift new file mode 100644 index 0000000000..0f69dbf79f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PhoneNumbers.swift @@ -0,0 +1,17 @@ +import Foundation +import TelegramCorePrivateModule + +private let phoneNumberUtil = NBPhoneNumberUtil() + +public func formatPhoneNumber(_ string: String) -> String { + do { + let number = try phoneNumberUtil.parse("+" + string, defaultRegion: nil) + return try phoneNumberUtil.format(number, numberFormat: .INTERNATIONAL) + } catch _ { + return string + } +} + +public func isViablePhoneNumber(_ string: String) -> Bool { + return phoneNumberUtil.isViablePhoneNumber(string) +} diff --git a/submodules/TelegramCore/TelegramCore/Polls.swift b/submodules/TelegramCore/TelegramCore/Polls.swift new file mode 100644 index 0000000000..4f3525b3f3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Polls.swift @@ -0,0 +1,73 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum RequestMessageSelectPollOptionError { + case generic +} + +public func requestMessageSelectPollOption(account: Account, messageId: MessageId, opaqueIdentifier: Data?) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> introduceError(RequestMessageSelectPollOptionError.self) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.sendVote(peer: inputPeer, msgId: messageId.id, options: opaqueIdentifier.flatMap({ [Buffer(data: $0)] }) ?? [])) + |> mapError { _ -> RequestMessageSelectPollOptionError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } + } else { + return .complete() + } + } +} + +public func requestClosePoll(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal { + return postbox.transaction { transaction -> (TelegramMediaPoll, Api.InputPeer)? in + guard let inputPeer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else { + return nil + } + guard let message = transaction.getMessage(messageId) else { + return nil + } + for media in message.media { + if let poll = media as? TelegramMediaPoll { + return (poll, inputPeer) + } + } + return nil + } + |> mapToSignal { pollAndInputPeer -> Signal in + guard let (poll, inputPeer) = pollAndInputPeer, poll.pollId.namespace == Namespaces.Media.CloudPoll else { + return .complete() + } + var flags: Int32 = 0 + flags |= 1 << 14 + return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(poll: .poll(id: poll.pollId.id, flags: 1 << 0, question: poll.text, answers: poll.options.map({ $0.apiOption }))), replyMarkup: nil, entities: nil)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/PrivacySettings.swift b/submodules/TelegramCore/TelegramCore/PrivacySettings.swift new file mode 100644 index 0000000000..13b373cc6c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/PrivacySettings.swift @@ -0,0 +1,191 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class SelectivePrivacyPeer: Equatable { + public let peer: Peer + public let participantCount: Int32? + + public init(peer: Peer, participantCount: Int32?) { + self.peer = peer + self.participantCount = participantCount + } + + public static func ==(lhs: SelectivePrivacyPeer, rhs: SelectivePrivacyPeer) -> Bool { + if !lhs.peer.isEqual(rhs.peer) { + return false + } + if lhs.participantCount != rhs.participantCount { + return false + } + return true + } + + public var userCount: Int { + if let participantCount = self.participantCount { + return Int(participantCount) + } else if let group = self.peer as? TelegramGroup { + return group.participantCount + } else { + return 1 + } + } +} + +public enum SelectivePrivacySettings: Equatable { + case enableEveryone(disableFor: [PeerId: SelectivePrivacyPeer]) + case enableContacts(enableFor: [PeerId: SelectivePrivacyPeer], disableFor: [PeerId: SelectivePrivacyPeer]) + case disableEveryone(enableFor: [PeerId: SelectivePrivacyPeer]) + + public static func ==(lhs: SelectivePrivacySettings, rhs: SelectivePrivacySettings) -> Bool { + switch lhs { + case let .enableEveryone(disableFor): + if case .enableEveryone(disableFor) = rhs { + return true + } else { + return false + } + case let .enableContacts(enableFor, disableFor): + if case .enableContacts(enableFor, disableFor) = rhs { + return true + } else { + return false + } + case let .disableEveryone(enableFor): + if case .disableEveryone(enableFor) = rhs { + return true + } else { + return false + } + } + } + + func withEnabledPeers(_ peers: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettings { + switch self { + case let .disableEveryone(enableFor): + return .disableEveryone(enableFor: enableFor.merging(peers, uniquingKeysWith: { lhs, rhs in lhs })) + case let .enableContacts(enableFor, disableFor): + return .enableContacts(enableFor: enableFor.merging(peers, uniquingKeysWith: { lhs, rhs in lhs }), disableFor: disableFor) + case .enableEveryone: + return self + } + } + + func withDisabledPeers(_ peers: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettings { + switch self { + case .disableEveryone: + return self + case let .enableContacts(enableFor, disableFor): + return .enableContacts(enableFor: enableFor, disableFor: disableFor.merging(peers, uniquingKeysWith: { lhs, rhs in lhs })) + case let .enableEveryone(disableFor): + return .enableEveryone(disableFor: disableFor.merging(peers, uniquingKeysWith: { lhs, rhs in lhs })) + } + } +} + +public struct AccountPrivacySettings: Equatable { + public let presence: SelectivePrivacySettings + public let groupInvitations: SelectivePrivacySettings + public let voiceCalls: SelectivePrivacySettings + public let voiceCallsP2P: SelectivePrivacySettings + public let profilePhoto: SelectivePrivacySettings + public let forwards: SelectivePrivacySettings + public let phoneNumber: SelectivePrivacySettings + + public let accountRemovalTimeout: Int32 + + public init(presence: SelectivePrivacySettings, groupInvitations: SelectivePrivacySettings, voiceCalls: SelectivePrivacySettings, voiceCallsP2P: SelectivePrivacySettings, profilePhoto: SelectivePrivacySettings, forwards: SelectivePrivacySettings, phoneNumber: SelectivePrivacySettings, accountRemovalTimeout: Int32) { + self.presence = presence + self.groupInvitations = groupInvitations + self.voiceCalls = voiceCalls + self.voiceCallsP2P = voiceCallsP2P + self.profilePhoto = profilePhoto + self.forwards = forwards + self.phoneNumber = phoneNumber + self.accountRemovalTimeout = accountRemovalTimeout + } + + public static func ==(lhs: AccountPrivacySettings, rhs: AccountPrivacySettings) -> Bool { + if lhs.presence != rhs.presence { + return false + } + if lhs.groupInvitations != rhs.groupInvitations { + return false + } + if lhs.voiceCalls != rhs.voiceCalls { + return false + } + if lhs.voiceCallsP2P != rhs.voiceCallsP2P { + return false + } + if lhs.profilePhoto != rhs.profilePhoto { + return false + } + if lhs.forwards != rhs.forwards { + return false + } + if lhs.phoneNumber != rhs.phoneNumber { + return false + } + if lhs.accountRemovalTimeout != rhs.accountRemovalTimeout { + return false + } + + return true + } +} + +extension SelectivePrivacySettings { + init(apiRules: [Api.PrivacyRule], peers: [PeerId: SelectivePrivacyPeer]) { + var current: SelectivePrivacySettings = .disableEveryone(enableFor: [:]) + + var disableFor: [PeerId: SelectivePrivacyPeer] = [:] + var enableFor: [PeerId: SelectivePrivacyPeer] = [:] + + for rule in apiRules { + switch rule { + case .privacyValueAllowAll: + current = .enableEveryone(disableFor: [:]) + case .privacyValueAllowContacts: + current = .enableContacts(enableFor: [:], disableFor: [:]) + case let .privacyValueAllowUsers(users): + for id in users { + if let peer = peers[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] { + enableFor[peer.peer.id] = peer + } + } + case .privacyValueDisallowAll: + break + case .privacyValueDisallowContacts: + break + case let .privacyValueDisallowUsers(users): + for id in users { + if let peer = peers[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] { + disableFor[peer.peer.id] = peer + } + } + case let .privacyValueAllowChatParticipants(chats): + for id in chats { + for possibleId in [PeerId(namespace: Namespaces.Peer.CloudGroup, id: id), PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)] { + if let peer = peers[possibleId] { + enableFor[peer.peer.id] = peer + } + } + } + case let .privacyValueDisallowChatParticipants(chats): + for id in chats { + for possibleId in [PeerId(namespace: Namespaces.Peer.CloudGroup, id: id), PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)] { + if let peer = peers[possibleId] { + disableFor[peer.peer.id] = peer + } + } + } + } + } + + self = current.withEnabledPeers(enableFor).withDisabledPeers(disableFor) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift b/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift new file mode 100644 index 0000000000..99011ea068 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift @@ -0,0 +1,986 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +private enum MessageParsingError: Error { + case contentParsingError + case unsupportedLayer + case invalidChatState + case alreadyProcessedMessageInSequenceBasedLayer + case holesInSequenceBasedLayer + case secretChatCorruption +} + +enum SecretChatRekeyServiceAction { + case pfsRequestKey(rekeySessionId: Int64, gA: MemoryBuffer) + case pfsAcceptKey(rekeySessionId: Int64, gB: MemoryBuffer, keyFingerprint: Int64) + case pfsAbortSession(rekeySessionId: Int64) + case pfsCommitKey(rekeySessionId: Int64, keyFingerprint: Int64) +} + +private enum SecretChatServiceAction { + case deleteMessages(globallyUniqueIds: [Int64]) + case clearHistory + case reportLayerSupport(Int32) + case markMessagesContentAsConsumed(globallyUniqueIds: [Int64]) + case setMessageAutoremoveTimeout(Int32) + case resendOperations(fromSeq: Int32, toSeq: Int32) + case rekeyAction(SecretChatRekeyServiceAction) +} + +private func parsedServiceAction(_ operation: SecretChatIncomingDecryptedOperation) -> SecretChatServiceAction? { + guard let parsedLayer = SecretChatLayer(rawValue: operation.layer) else { + return nil + } + + switch parsedLayer { + case .layer8: + if let parsedObject = SecretApi8.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi8.DecryptedMessage { + return SecretChatServiceAction(apiMessage) + } + case .layer46: + if let parsedObject = SecretApi46.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi46.DecryptedMessage { + return SecretChatServiceAction(apiMessage) + } + case .layer73: + if let parsedObject = SecretApi73.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi73.DecryptedMessage { + return SecretChatServiceAction(apiMessage) + } + } + return nil +} + +struct SecretChatOperationProcessResult { + let addedMessages: [StoreMessage] +} + +func processSecretChatIncomingDecryptedOperations(mediaBox: MediaBox, transaction: Transaction, peerId: PeerId) -> SecretChatOperationProcessResult { + if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + var removeTagLocalIndices: [Int32] = [] + var updatedState = state + var couldNotResendRequestedMessages = false + var maxAcknowledgedCanonicalOperationIndex: Int32? + var updatedPeer = peer + var addedMessages: [StoreMessage] = [] + + transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted, { entry in + if let operation = entry.contents as? SecretChatIncomingDecryptedOperation, let serviceAction = parsedServiceAction(operation), case let .resendOperations(fromSeq, toSeq) = serviceAction { + switch updatedState.role { + case .creator: + if fromSeq < 0 || toSeq < 0 || (fromSeq & 1) == 0 || (toSeq & 1) == 0 { + return true + } + case .participant: + if fromSeq < 0 || toSeq < 0 || (fromSeq & 1) != 0 || (toSeq & 1) != 0 { + return true + } + } + switch updatedState.embeddedState { + case let .sequenceBasedLayer(sequenceState): + let fromOperationIndex = sequenceState.outgoingOperationIndexFromCanonicalOperationIndex(fromSeq / 2) + let toOperationIndex = sequenceState.outgoingOperationIndexFromCanonicalOperationIndex(toSeq / 2) + if fromOperationIndex <= toOperationIndex { + for index in fromOperationIndex ... toOperationIndex { + var notFound = false + transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: index, { entry in + if let _ = entry { return PeerOperationLogEntryUpdate(mergedIndex: .newAutomatic, contents: .none) + } else { + notFound = true + return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) + } + }) + if notFound { + couldNotResendRequestedMessages = true + return false + } + } + } + default: + break + } + } + return true + }) + + if !couldNotResendRequestedMessages { + transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted, { entry in + if let operation = entry.contents as? SecretChatIncomingDecryptedOperation { + do { + var message: StoreMessage? + var contentParsingError = false + var resources: [(MediaResource, Data)] = [] + var serviceAction: SecretChatServiceAction? + + guard let parsedLayer = SecretChatLayer(rawValue: operation.layer) else { + throw MessageParsingError.unsupportedLayer + } + + switch parsedLayer { + case .layer8: + if let parsedObject = SecretApi8.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi8.DecryptedMessage { + message = StoreMessage(peerId: peerId, authorId: updatedPeer.regularPeerId, tagLocalIndex: entry.tagLocalIndex, timestamp: operation.timestamp, apiMessage: apiMessage, file: operation.file) + serviceAction = SecretChatServiceAction(apiMessage) + } else { + throw MessageParsingError.contentParsingError + } + case .layer46: + if let parsedObject = SecretApi46.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi46.DecryptedMessage { + if let (parsedMessage, parsedResources) = parseMessage(peerId: peerId, authorId: updatedPeer.regularPeerId, tagLocalIndex: entry.tagLocalIndex, timestamp: operation.timestamp, apiMessage: apiMessage, file: operation.file, messageIdForGloballyUniqueMessageId: { id in + return transaction.messageIdForGloballyUniqueMessageId(peerId: peerId, id: id) + }) { + message = parsedMessage + resources = parsedResources + } + serviceAction = SecretChatServiceAction(apiMessage) + } else { + throw MessageParsingError.contentParsingError + } + case .layer73: + if let parsedObject = SecretApi73.parse(Buffer(bufferNoCopy: operation.contents)), let apiMessage = parsedObject as? SecretApi73.DecryptedMessage { + if let (parsedMessage, parsedResources) = parseMessage(peerId: peerId, authorId: updatedPeer.regularPeerId, tagLocalIndex: entry.tagLocalIndex, timestamp: operation.timestamp, apiMessage: apiMessage, file: operation.file, messageIdForGloballyUniqueMessageId: { id in + return transaction.messageIdForGloballyUniqueMessageId(peerId: peerId, id: id) + }) { + message = parsedMessage + resources = parsedResources + } + serviceAction = SecretChatServiceAction(apiMessage) + } else { + contentParsingError = true + } + } + + switch updatedState.embeddedState { + case .terminated: + throw MessageParsingError.invalidChatState + case .handshake: + throw MessageParsingError.invalidChatState + case .basicLayer: + if parsedLayer != .layer8 { + throw MessageParsingError.contentParsingError + } + case let .sequenceBasedLayer(sequenceState): + if let sequenceInfo = operation.sequenceInfo { + let canonicalIncomingIndex = sequenceState.canonicalIncomingOperationIndex(entry.tagLocalIndex) + assert(canonicalIncomingIndex == sequenceInfo.operationIndex) + if let topProcessedCanonicalIncomingOperationIndex = sequenceState.topProcessedCanonicalIncomingOperationIndex { + if canonicalIncomingIndex != topProcessedCanonicalIncomingOperationIndex + 1 { + if canonicalIncomingIndex <= topProcessedCanonicalIncomingOperationIndex { + throw MessageParsingError.alreadyProcessedMessageInSequenceBasedLayer + } else { + if let layer = SecretChatSequenceBasedLayer(rawValue: parsedLayer.rawValue) { + let role = updatedState.role + let fromSeqNo: Int32 = (topProcessedCanonicalIncomingOperationIndex + 1) * 2 + (role == .creator ? 0 : 1) + let toSeqNo: Int32 = (canonicalIncomingIndex - 1) * 2 + (role == .creator ? 0 : 1) + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.resendOperations(layer: layer, actionGloballyUniqueId: arc4random64(), fromSeqNo: fromSeqNo, toSeqNo: toSeqNo), state: updatedState) + } else { + assertionFailure() + } + throw MessageParsingError.holesInSequenceBasedLayer + } + } + } else { + + if canonicalIncomingIndex != 0 && canonicalIncomingIndex != 1 { + if let layer = SecretChatSequenceBasedLayer(rawValue: parsedLayer.rawValue) { + let role = updatedState.role + let fromSeqNo: Int32 = Int32(0 * 2) + (role == .creator ? Int32(0) : Int32(1)) + let toSeqNo: Int32 = (canonicalIncomingIndex - 1) * 2 + (role == .creator ? 0 : 1) + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.resendOperations(layer: layer, actionGloballyUniqueId: arc4random64(), fromSeqNo: fromSeqNo, toSeqNo: toSeqNo), state: updatedState) + } else { + assertionFailure() + } + throw MessageParsingError.holesInSequenceBasedLayer + } + } + + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedTopProcessedCanonicalIncomingOperationIndex(canonicalIncomingIndex))) + } else { + throw MessageParsingError.contentParsingError + } + } + + if let serviceAction = serviceAction { + switch serviceAction { + case let .reportLayerSupport(layerSupport): + switch updatedState.embeddedState { + case .terminated: + throw MessageParsingError.invalidChatState + case .handshake: + throw MessageParsingError.invalidChatState + case .basicLayer: + if layerSupport >= 73 { + let sequenceBasedLayerState = SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer73, locallyRequestedLayer: 73, remotelyRequestedLayer: layerSupport), rekeyState: nil, baseIncomingOperationIndex: entry.tagLocalIndex, baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceBasedLayerState)) + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer73, actionGloballyUniqueId: arc4random64(), layerSupport: 73), state: updatedState) + } else if layerSupport >= 46 { + let sequenceBasedLayerState = SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: 46, remotelyRequestedLayer: layerSupport), rekeyState: nil, baseIncomingOperationIndex: entry.tagLocalIndex, baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceBasedLayerState)) + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer46, actionGloballyUniqueId: arc4random64(), layerSupport: 73), state: updatedState) + } else { + throw MessageParsingError.contentParsingError + } + case let .sequenceBasedLayer(sequenceState): + if sequenceState.layerNegotiationState.remotelyRequestedLayer != layerSupport { + let updatedNegotiationState = sequenceState.layerNegotiationState.withUpdatedRemotelyRequestedLayer(layerSupport) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedLayerNegotiationState(updatedNegotiationState))) + + updatedState = secretChatCheckLayerNegotiationIfNeeded(transaction: transaction, peerId: peerId, state: updatedState) + } + } + case let .setMessageAutoremoveTimeout(timeout): + updatedPeer = updatedPeer.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout) + updatedState = updatedState.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout) + case let .rekeyAction(action): + updatedState = secretChatAdvanceRekeySessionIfNeeded(transaction: transaction, peerId: peerId, state: updatedState, action: action) + case let .deleteMessages(globallyUniqueIds): + var messageIds: [MessageId] = [] + for id in globallyUniqueIds { + if let messageId = transaction.messageIdForGloballyUniqueMessageId(peerId: peerId, id: id) { + messageIds.append(messageId) + } + } + if !messageIds.isEmpty { + var filteredMessageIds = messageIds + outer: for i in (0 ..< filteredMessageIds.count).reversed() { + if let message = transaction.getMessage(filteredMessageIds[i]) { + for media in message.media { + if let media = media as? TelegramMediaAction { + if case .historyScreenshot = media.action { + filteredMessageIds.remove(at: i) + continue outer + } + } + } + } + } + deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: filteredMessageIds) + } + case .clearHistory: + clearHistory(transaction: transaction, mediaBox: mediaBox, peerId: peerId) + case let .markMessagesContentAsConsumed(globallyUniqueIds): + var messageIds: [MessageId] = [] + for id in globallyUniqueIds { + if let messageId = transaction.messageIdForGloballyUniqueMessageId(peerId: peerId, id: id) { + messageIds.append(messageId) + } + } + for messageId in messageIds { + markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId) + } + default: + break + } + } + + removeTagLocalIndices.append(entry.tagLocalIndex) + + if let sequenceInfo = operation.sequenceInfo { + if maxAcknowledgedCanonicalOperationIndex == nil || maxAcknowledgedCanonicalOperationIndex! < sequenceInfo.topReceivedOperationIndex { + maxAcknowledgedCanonicalOperationIndex = sequenceInfo.topReceivedOperationIndex + } + } + + if let message = message { + for (resource, data) in resources { + mediaBox.storeResourceData(resource.id, data: data) + } + let _ = transaction.addMessages([message], location: .Random) + addedMessages.append(message) + } else if contentParsingError { + Logger.shared.log("SecretChat", "Couldn't parse secret message content") + } + } catch let error { + if let error = error as? MessageParsingError { + switch error { + case .contentParsingError: + Logger.shared.log("SecretChat", "Couldn't parse secret message payload") + removeTagLocalIndices.append(entry.tagLocalIndex) + return true + case .unsupportedLayer: + return false + case .invalidChatState: + removeTagLocalIndices.append(entry.tagLocalIndex) + return false + case .alreadyProcessedMessageInSequenceBasedLayer: + removeTagLocalIndices.append(entry.tagLocalIndex) + return true + case .holesInSequenceBasedLayer: + Logger.shared.log("SecretChat", "Found holes in incoming operation sequence") + return false + case .secretChatCorruption: + Logger.shared.log("SecretChat", "Secret chat corrupted") + return false + } + } else { + assertionFailure() + } + } + } else { + assertionFailure() + } + return true + }) + } + for index in removeTagLocalIndices { + let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted, tagLocalIndex: index) + assert(removed) + } + if let maxAcknowledgedCanonicalOperationIndex = maxAcknowledgedCanonicalOperationIndex { + switch updatedState.embeddedState { + case let .sequenceBasedLayer(sequenceState): + let tagLocalIndex = max(-1, sequenceState.outgoingOperationIndexFromCanonicalOperationIndex(maxAcknowledgedCanonicalOperationIndex) - 1) + if tagLocalIndex >= 0 { + Logger.shared.log("SecretChat", "peer \(peerId) dropping acknowledged operations <= \(tagLocalIndex)") + transaction.operationLogRemoveEntries(peerId: peerId, tag: OperationLogTags.SecretOutgoing, withTagLocalIndicesEqualToOrLowerThan: tagLocalIndex) + } + default: + break + } + } + if updatedState != state { + transaction.setPeerChatState(peerId, state: updatedState) + updatedPeer = updatedPeer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState) + } + if !peer.isEqual(updatedPeer) { + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + } + return SecretChatOperationProcessResult(addedMessages: addedMessages) + } else { + assertionFailure() + return SecretChatOperationProcessResult(addedMessages: []) + } +} + +extension SecretChatServiceAction { + init?(_ apiMessage: SecretApi8.DecryptedMessage) { + switch apiMessage { + case .decryptedMessage: + return nil + case let .decryptedMessageService(_, _, action): + switch action { + case let .decryptedMessageActionDeleteMessages(randomIds): + self = .deleteMessages(globallyUniqueIds: randomIds) + case .decryptedMessageActionFlushHistory: + self = .clearHistory + case let .decryptedMessageActionNotifyLayer(layer): + self = .reportLayerSupport(layer) + case let .decryptedMessageActionReadMessages(randomIds): + self = .markMessagesContentAsConsumed(globallyUniqueIds: randomIds) + case .decryptedMessageActionScreenshotMessages: + return nil + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + self = .setMessageAutoremoveTimeout(ttlSeconds) + } + } + } +} + +extension SecretChatServiceAction { + init?(_ apiMessage: SecretApi46.DecryptedMessage) { + switch apiMessage { + case .decryptedMessage: + return nil + case let .decryptedMessageService(_, action): + switch action { + case let .decryptedMessageActionDeleteMessages(randomIds): + self = .deleteMessages(globallyUniqueIds: randomIds) + case .decryptedMessageActionFlushHistory: + self = .clearHistory + case let .decryptedMessageActionNotifyLayer(layer): + self = .reportLayerSupport(layer) + case let .decryptedMessageActionReadMessages(randomIds): + self = .markMessagesContentAsConsumed(globallyUniqueIds: randomIds) + case .decryptedMessageActionScreenshotMessages: + return nil + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + self = .setMessageAutoremoveTimeout(ttlSeconds) + case let .decryptedMessageActionResend(startSeqNo, endSeqNo): + self = .resendOperations(fromSeq: startSeqNo, toSeq: endSeqNo) + case let .decryptedMessageActionRequestKey(exchangeId, gA): + self = .rekeyAction(.pfsRequestKey(rekeySessionId: exchangeId, gA: MemoryBuffer(gA))) + case let .decryptedMessageActionAcceptKey(exchangeId, gB, keyFingerprint): + self = .rekeyAction(.pfsAcceptKey(rekeySessionId: exchangeId, gB: MemoryBuffer(gB), keyFingerprint: keyFingerprint)) + case let .decryptedMessageActionCommitKey(exchangeId, keyFingerprint): + self = .rekeyAction(.pfsCommitKey(rekeySessionId: exchangeId, keyFingerprint: keyFingerprint)) + case let .decryptedMessageActionAbortKey(exchangeId): + self = .rekeyAction(.pfsAbortSession(rekeySessionId: exchangeId)) + case .decryptedMessageActionNoop: + return nil + } + } + } +} + +extension SecretChatServiceAction { + init?(_ apiMessage: SecretApi73.DecryptedMessage) { + switch apiMessage { + case .decryptedMessage: + return nil + case let .decryptedMessageService(_, action): + switch action { + case let .decryptedMessageActionDeleteMessages(randomIds): + self = .deleteMessages(globallyUniqueIds: randomIds) + case .decryptedMessageActionFlushHistory: + self = .clearHistory + case let .decryptedMessageActionNotifyLayer(layer): + self = .reportLayerSupport(layer) + case let .decryptedMessageActionReadMessages(randomIds): + self = .markMessagesContentAsConsumed(globallyUniqueIds: randomIds) + case .decryptedMessageActionScreenshotMessages: + return nil + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + self = .setMessageAutoremoveTimeout(ttlSeconds) + case let .decryptedMessageActionResend(startSeqNo, endSeqNo): + self = .resendOperations(fromSeq: startSeqNo, toSeq: endSeqNo) + case let .decryptedMessageActionRequestKey(exchangeId, gA): + self = .rekeyAction(.pfsRequestKey(rekeySessionId: exchangeId, gA: MemoryBuffer(gA))) + case let .decryptedMessageActionAcceptKey(exchangeId, gB, keyFingerprint): + self = .rekeyAction(.pfsAcceptKey(rekeySessionId: exchangeId, gB: MemoryBuffer(gB), keyFingerprint: keyFingerprint)) + case let .decryptedMessageActionCommitKey(exchangeId, keyFingerprint): + self = .rekeyAction(.pfsCommitKey(rekeySessionId: exchangeId, keyFingerprint: keyFingerprint)) + case let .decryptedMessageActionAbortKey(exchangeId): + self = .rekeyAction(.pfsAbortSession(rekeySessionId: exchangeId)) + case .decryptedMessageActionNoop: + return nil + } + } + } +} + +extension StoreMessage { + convenience init?(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi8.DecryptedMessage, file: SecretChatFileReference?) { + switch apiMessage { + case let .decryptedMessage(randomId, _, message, media): + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: message, attributes: [], media: []) + case let .decryptedMessageService(randomId, _, action): + switch action { + case let .decryptedMessageActionDeleteMessages(randomIds): + return nil + case .decryptedMessageActionFlushHistory: + return nil + case let .decryptedMessageActionNotifyLayer(layer): + return nil + case let .decryptedMessageActionReadMessages(randomIds): + return nil + case .decryptedMessageActionScreenshotMessages: + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]) + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(ttlSeconds))]) + } + } + } +} + +extension TelegramMediaFileAttribute { + init?(_ apiAttribute: SecretApi46.DocumentAttribute) { + switch apiAttribute { + case .documentAttributeAnimated: + self = .Animated + case let .documentAttributeAudio(flags, duration, title, performer, waveform): + let isVoice = (flags & (1 << 10)) != 0 + var waveformBuffer: MemoryBuffer? + if let waveform = waveform { + let memory = malloc(waveform.size)! + memcpy(memory, waveform.data, waveform.size) + waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) + } + self = .Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer) + case let .documentAttributeFilename(fileName): + self = .FileName(fileName: fileName) + case let .documentAttributeImageSize(w, h): + self = .ImageSize(size: CGSize(width: CGFloat(w), height: CGFloat(h))) + case let .documentAttributeSticker(alt, stickerset): + let packReference: StickerPackReference? + switch stickerset { + case .inputStickerSetEmpty: + packReference = nil + case let .inputStickerSetShortName(shortName): + packReference = .name(shortName) + } + self = .Sticker(displayText: alt, packReference: packReference, maskData: nil) + case let .documentAttributeVideo(duration, w, h): + self = .Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h)), flags: []) + } + } +} + +extension TelegramMediaFileAttribute { + init?(_ apiAttribute: SecretApi73.DocumentAttribute) { + switch apiAttribute { + case .documentAttributeAnimated: + self = .Animated + case let .documentAttributeAudio(flags, duration, title, performer, waveform): + let isVoice = (flags & (1 << 10)) != 0 + var waveformBuffer: MemoryBuffer? + if let waveform = waveform { + let memory = malloc(waveform.size)! + memcpy(memory, waveform.data, waveform.size) + waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) + } + self = .Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer) + case let .documentAttributeFilename(fileName): + self = .FileName(fileName: fileName) + case let .documentAttributeImageSize(w, h): + self = .ImageSize(size: CGSize(width: CGFloat(w), height: CGFloat(h))) + case let .documentAttributeSticker(alt, stickerset): + let packReference: StickerPackReference? + switch stickerset { + case .inputStickerSetEmpty: + packReference = nil + case let .inputStickerSetShortName(shortName): + packReference = .name(shortName) + } + self = .Sticker(displayText: alt, packReference: packReference, maskData: nil) + case let .documentAttributeVideo(flags, duration, w, h): + var videoFlags: TelegramMediaVideoFlags = [] + if (flags & (1 << 0)) != 0 { + videoFlags.insert(.instantRoundVideo) + } + self = .Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h)), flags: videoFlags) + } + } +} + +private func parseEntities(_ entities: [SecretApi46.MessageEntity]?) -> TextEntitiesMessageAttribute { + var result: [MessageTextEntity] = [] + if let entities = entities { + for entity in entities { + switch entity { + case let .messageEntityMention(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Mention)) + case let .messageEntityHashtag(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) + case let .messageEntityBotCommand(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BotCommand)) + case let .messageEntityUrl(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Url)) + case let .messageEntityEmail(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Email)) + case let .messageEntityBold(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Bold)) + case let .messageEntityItalic(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Italic)) + case let .messageEntityCode(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Code)) + case let .messageEntityPre(offset, length, _): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Pre)) + case let .messageEntityTextUrl(offset, length, url): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextUrl(url: url))) + case .messageEntityUnknown: + break + } + } + } + return TextEntitiesMessageAttribute(entities: result) +} + +private func maximumMediaAutoremoveTimeout(_ media: [Media]) -> Int32 { + var maxDuration: Int32 = 0 + for media in media { + if let file = media as? TelegramMediaFile { + if let duration = file.duration { + maxDuration = max(maxDuration, duration) + } + } + } + return maxDuration +} + +private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi46.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? { + switch apiMessage { + case let .decryptedMessage(_, randomId, ttl, message, media, entities, viaBotName, replyToRandomId): + var text = message + var parsedMedia: [Media] = [] + var attributes: [MessageAttribute] = [] + var resources: [(MediaResource, Data)] = [] + + attributes.append(parseEntities(entities)) + + if let viaBotName = viaBotName, !viaBotName.isEmpty { + attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName)) + } + + if let media = media { + switch media { + case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + var representations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size))) + let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil) + parsedMedia.append(image) + } + case let .decryptedMessageMediaAudio(duration, mimeType, size, key, iv): + if let file = file { + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: [TelegramMediaFileAttribute.Audio(isVoice: true, duration: Int(duration), title: nil, performer: nil, waveform: nil)]) + parsedMedia.append(fileMedia) + } + case let .decryptedMessageMediaDocument(thumb, thumbW, thumbH, mimeType, size, key, iv, attributes, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + var parsedAttributes: [TelegramMediaFileAttribute] = [] + for attribute in attributes { + if let parsedAttribute = TelegramMediaFileAttribute(attribute) { + parsedAttributes.append(parsedAttribute) + } + } + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + } + case let .decryptedMessageMediaVideo(thumb, thumbW, thumbH, duration, mimeType, w, h, size, key, iv, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + let parsedAttributes: [TelegramMediaFileAttribute] = [.Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h)), flags: []), .FileName(fileName: "video.mov")] + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + } + case let .decryptedMessageMediaExternalDocument(id, accessHash, _, mimeType, size, thumb, dcId, attributes): + var parsedAttributes: [TelegramMediaFileAttribute] = [] + for attribute in attributes { + if let parsedAttribute = TelegramMediaFileAttribute(attribute) { + parsedAttributes.append(parsedAttribute) + } + } + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + switch thumb { + case let .photoSize(_, location, w, h, size): + switch location { + case let .fileLocation(dcId, volumeId, localId, secret): + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: CloudFileMediaResource(datacenterId: Int(dcId), volumeId: volumeId, localId: localId, secret: secret, size: size == 0 ? nil : Int(size), fileReference: nil))) + case .fileLocationUnavailable: + break + } + case let .photoCachedSize(_, location, w, h, bytes): + if bytes.size > 0 { + switch location { + case let .fileLocation(dcId, volumeId, localId, secret): + let resource = CloudFileMediaResource(datacenterId: Int(dcId), volumeId: volumeId, localId: localId, secret: secret, size: bytes.size, fileReference: nil) + resources.append((resource, bytes.makeData())) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + case .fileLocationUnavailable: + break + } + } + default: + break + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: Int(size), fileReference: nil, fileName: nil), previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + case let .decryptedMessageMediaWebPage(url): + parsedMedia.append(TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.LocalWebpage, id: arc4random64()), content: .Pending(0, url))) + case let .decryptedMessageMediaGeoPoint(lat, long): + parsedMedia.append(TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil)) + case let .decryptedMessageMediaContact(phoneNumber, firstName, lastName, userId): + parsedMedia.append(TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: userId == 0 ? nil : PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), vCardData: nil)) + case let .decryptedMessageMediaVenue(lat, long, title, address, provider, venueId): + parsedMedia.append(TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: MapVenue(title: title, address: address, provider: provider, id: venueId, type: nil), liveBroadcastingTimeout: nil)) + case .decryptedMessageMediaEmpty: + break + } + } + + if ttl > 0 { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: ttl, countdownBeginTime: nil)) + } + + if let replyToRandomId = replyToRandomId, let replyMessageId = messageIdForGloballyUniqueMessageId(replyToRandomId) { + attributes.append(ReplyMessageAttribute(messageId: replyMessageId)) + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + break + } + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities) + + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources) + case let .decryptedMessageService(randomId, action): + switch action { + case let .decryptedMessageActionDeleteMessages(randomIds): + return nil + case .decryptedMessageActionFlushHistory: + return nil + case .decryptedMessageActionNotifyLayer: + return nil + case .decryptedMessageActionReadMessages: + return nil + case .decryptedMessageActionScreenshotMessages: + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), []) + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(ttlSeconds))]), []) + case .decryptedMessageActionResend: + return nil + case .decryptedMessageActionRequestKey: + return nil + case .decryptedMessageActionAcceptKey: + return nil + case .decryptedMessageActionCommitKey: + return nil + case .decryptedMessageActionAbortKey: + return nil + case .decryptedMessageActionNoop: + return nil + } + } +} + +private func parseEntities(_ entities: [SecretApi73.MessageEntity]) -> TextEntitiesMessageAttribute { + var result: [MessageTextEntity] = [] + for entity in entities { + switch entity { + case let .messageEntityMention(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Mention)) + case let .messageEntityHashtag(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) + case let .messageEntityBotCommand(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BotCommand)) + case let .messageEntityUrl(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Url)) + case let .messageEntityEmail(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Email)) + case let .messageEntityBold(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Bold)) + case let .messageEntityItalic(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Italic)) + case let .messageEntityCode(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Code)) + case let .messageEntityPre(offset, length, _): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Pre)) + case let .messageEntityTextUrl(offset, length, url): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextUrl(url: url))) + case .messageEntityUnknown: + break + } + } + return TextEntitiesMessageAttribute(entities: result) +} + +private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi73.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? { + switch apiMessage { + case let .decryptedMessage(_, randomId, ttl, message, media, entities, viaBotName, replyToRandomId, groupedId): + var text = message + var parsedMedia: [Media] = [] + var attributes: [MessageAttribute] = [] + var resources: [(MediaResource, Data)] = [] + + if let entitiesAttribute = entities.flatMap(parseEntities) { + attributes.append(entitiesAttribute) + } + + if let viaBotName = viaBotName, !viaBotName.isEmpty { + attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName)) + } + + if let media = media { + switch media { + case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + var representations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size))) + let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil) + parsedMedia.append(image) + } + case let .decryptedMessageMediaAudio(duration, mimeType, size, key, iv): + if let file = file { + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: [TelegramMediaFileAttribute.Audio(isVoice: true, duration: Int(duration), title: nil, performer: nil, waveform: nil)]) + parsedMedia.append(fileMedia) + attributes.append(ConsumableContentMessageAttribute(consumed: false)) + } + case let .decryptedMessageMediaDocument(thumb, thumbW, thumbH, mimeType, size, key, iv, decryptedAttributes, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + var parsedAttributes: [TelegramMediaFileAttribute] = [] + for attribute in decryptedAttributes { + if let parsedAttribute = TelegramMediaFileAttribute(attribute) { + parsedAttributes.append(parsedAttribute) + } + } + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + + loop: for attr in parsedAttributes { + switch attr { + case let .Video(_, _, flags): + if flags.contains(.instantRoundVideo) { + attributes.append(ConsumableContentMessageAttribute(consumed: false)) + } + break loop + case let .Audio(isVoice, _, _, _, _): + if isVoice { + attributes.append(ConsumableContentMessageAttribute(consumed: false)) + } + default: + break + } + } + } + case let .decryptedMessageMediaVideo(thumb, thumbW, thumbH, duration, mimeType, w, h, size, key, iv, caption): + if !caption.isEmpty { + text = caption + } + if let file = file { + let parsedAttributes: [TelegramMediaFileAttribute] = [.Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h)), flags: []), .FileName(fileName: "video.mov")] + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if thumb.size != 0 { + let resource = LocalFileMediaResource(fileId: arc4random64()) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(thumbW), height: CGFloat(thumbH)), resource: resource)) + resources.append((resource, thumb.makeData())) + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + } + case let .decryptedMessageMediaExternalDocument(id, accessHash, date, mimeType, size, thumb, dcId, attributes): + var parsedAttributes: [TelegramMediaFileAttribute] = [] + for attribute in attributes { + if let parsedAttribute = TelegramMediaFileAttribute(attribute) { + parsedAttributes.append(parsedAttribute) + } + } + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + switch thumb { + case let .photoSize(_, location, w, h, size): + switch location { + case let .fileLocation(dcId, volumeId, localId, secret): + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: CloudFileMediaResource(datacenterId: Int(dcId), volumeId: volumeId, localId: localId, secret: secret, size: size == 0 ? nil : Int(size), fileReference: nil))) + case .fileLocationUnavailable: + break + } + case let .photoCachedSize(_, location, w, h, bytes): + if bytes.size > 0 { + switch location { + case let .fileLocation(dcId, volumeId, localId, secret): + let resource = CloudFileMediaResource(datacenterId: Int(dcId), volumeId: volumeId, localId: localId, secret: secret, size: bytes.size, fileReference: nil) + resources.append((resource, bytes.makeData())) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + case .fileLocationUnavailable: + break + } + } + default: + break + } + let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: Int(size), fileReference: nil, fileName: nil), previewRepresentations: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + parsedMedia.append(fileMedia) + case let .decryptedMessageMediaWebPage(url): + parsedMedia.append(TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.LocalWebpage, id: arc4random64()), content: .Pending(0, url))) + case let .decryptedMessageMediaGeoPoint(lat, long): + parsedMedia.append(TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil)) + case let .decryptedMessageMediaContact(phoneNumber, firstName, lastName, userId): + parsedMedia.append(TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: userId == 0 ? nil : PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), vCardData: nil)) + case let .decryptedMessageMediaVenue(lat, long, title, address, provider, venueId): + parsedMedia.append(TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: MapVenue(title: title, address: address, provider: provider, id: venueId, type: nil), liveBroadcastingTimeout: nil)) + case .decryptedMessageMediaEmpty: + break + } + } + + if ttl > 0 { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: ttl, countdownBeginTime: nil)) + } + + var groupingKey: Int64? + if let groupedId = groupedId { + inner: for media in parsedMedia { + if let _ = media as? TelegramMediaImage { + groupingKey = groupedId + break inner + } else if let _ = media as? TelegramMediaFile { + groupingKey = groupedId + break inner + } + } + } + + if let replyToRandomId = replyToRandomId, let replyMessageId = messageIdForGloballyUniqueMessageId(replyToRandomId) { + attributes.append(ReplyMessageAttribute(messageId: replyMessageId)) + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + for attribute in attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + entitiesAttribute = attribute + break + } + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities) + + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: groupingKey, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources) + case let .decryptedMessageService(randomId, action): + switch action { + case .decryptedMessageActionDeleteMessages: + return nil + case .decryptedMessageActionFlushHistory: + return nil + case .decryptedMessageActionNotifyLayer: + return nil + case .decryptedMessageActionReadMessages: + return nil + case .decryptedMessageActionScreenshotMessages: + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), []) + case let .decryptedMessageActionSetMessageTTL(ttlSeconds): + return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(ttlSeconds))]), []) + case .decryptedMessageActionResend: + return nil + case .decryptedMessageActionRequestKey: + return nil + case .decryptedMessageActionAcceptKey: + return nil + case .decryptedMessageActionCommitKey: + return nil + case .decryptedMessageActionAbortKey: + return nil + case .decryptedMessageActionNoop: + return nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingEncryptedOperations.swift b/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingEncryptedOperations.swift new file mode 100644 index 0000000000..562cf0b7e2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ProcessSecretChatIncomingEncryptedOperations.swift @@ -0,0 +1,149 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private enum MessagePreParsingError: Error { + case invalidChatState + case malformedData + case protocolViolation +} + +func processSecretChatIncomingEncryptedOperations(transaction: Transaction, peerId: PeerId) -> Bool { + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var updatedState = state + var removeTagLocalIndices: [Int32] = [] + var addedDecryptedOperations = false + transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SecretIncomingEncrypted, { entry in + if let operation = entry.contents as? SecretChatIncomingEncryptedOperation { + if let key = updatedState.keychain.key(fingerprint: operation.keyFingerprint) { + var decryptedContents = withDecryptedMessageContents(parameters: SecretChatEncryptionParameters(key: key, mode: .v2(role: updatedState.role)), data: operation.contents) + if decryptedContents == nil { + decryptedContents = withDecryptedMessageContents(parameters: SecretChatEncryptionParameters(key: key, mode: .v1), data: operation.contents) + } + if let decryptedContents = decryptedContents { + withExtendedLifetime(decryptedContents, { + let buffer = BufferReader(Buffer(bufferNoCopy: decryptedContents)) + + do { + guard let topLevelSignature = buffer.readInt32() else { + throw MessagePreParsingError.malformedData + } + let parsedLayer: Int32 + let sequenceInfo: SecretChatOperationSequenceInfo? + + if topLevelSignature == 0x1be31789 { + guard let _ = parseBytes(buffer) else { + throw MessagePreParsingError.malformedData + } + + guard let layerValue = buffer.readInt32() else { + throw MessagePreParsingError.malformedData + } + + guard let seqInValue = buffer.readInt32() else { + throw MessagePreParsingError.malformedData + } + + guard let seqOutValue = buffer.readInt32() else { + throw MessagePreParsingError.malformedData + } + + switch updatedState.role { + case .creator: + if seqOutValue < 0 || (seqInValue >= 0 && (seqInValue & 1) == 0) || (seqOutValue & 1) != 0 { + throw MessagePreParsingError.protocolViolation + } + case .participant: + if seqOutValue < 0 || (seqInValue >= 0 && (seqInValue & 1) != 0) || (seqOutValue & 1) == 0 { + throw MessagePreParsingError.protocolViolation + } + } + + sequenceInfo = SecretChatOperationSequenceInfo(topReceivedOperationIndex: seqInValue / 2, operationIndex: seqOutValue / 2) + + if layerValue == 17 { + parsedLayer = 46 + } else { + parsedLayer = layerValue + } + } else { + parsedLayer = 8 + sequenceInfo = nil + buffer.reset() + } + + guard let messageContents = buffer.readBuffer(decryptedContents.length - Int(buffer.offset)) else { + throw MessagePreParsingError.malformedData + } + + let entryTagLocalIndex: StorePeerOperationLogEntryTagLocalIndex + + switch updatedState.embeddedState { + case .terminated: + throw MessagePreParsingError.invalidChatState + case .handshake: + throw MessagePreParsingError.invalidChatState + case .basicLayer: + if parsedLayer >= 46 { + guard let sequenceInfo = sequenceInfo else { + throw MessagePreParsingError.protocolViolation + } + + let sequenceBasedLayerState = SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: secretChatCommonSupportedLayer(remoteLayer: parsedLayer), locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: entry.tagLocalIndex, baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceBasedLayerState)) + transaction.setPeerChatState(peerId, state: updatedState) + entryTagLocalIndex = .manual(sequenceBasedLayerState.baseIncomingOperationIndex + sequenceInfo.operationIndex) + } else { + if parsedLayer != 8 && parsedLayer != 17 { + throw MessagePreParsingError.protocolViolation + } + entryTagLocalIndex = .automatic + } + case let .sequenceBasedLayer(sequenceState): + if parsedLayer < 46 { + throw MessagePreParsingError.protocolViolation + } + + entryTagLocalIndex = .manual(sequenceState.baseIncomingOperationIndex + sequenceInfo!.operationIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted, tagLocalIndex: entryTagLocalIndex, tagMergedIndex: .none, contents: SecretChatIncomingDecryptedOperation(timestamp: operation.timestamp, layer: parsedLayer, sequenceInfo: sequenceInfo, contents: MemoryBuffer(messageContents), file: operation.mediaFileReference)) + addedDecryptedOperations = true + } catch let error { + if let error = error as? MessagePreParsingError { + switch error { + case .invalidChatState: + break + case .malformedData, .protocolViolation: + break + } + } + Logger.shared.log("SecretChat", "peerId \(peerId) malformed data after decryption") + } + + removeTagLocalIndices.append(entry.tagLocalIndex) + }) + } else { + Logger.shared.log("SecretChat", "peerId \(peerId) couldn't decrypt message content") + removeTagLocalIndices.append(entry.tagLocalIndex) + } + } else { + Logger.shared.log("SecretChat", "peerId \(peerId) key \(operation.keyFingerprint) doesn't exist") + } + } else { + assertionFailure() + } + return true + }) + for index in removeTagLocalIndices { + let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretIncomingEncrypted, tagLocalIndex: index) + assert(removed) + } + return addedDecryptedOperations + } else { + return false + } +} diff --git a/submodules/TelegramCore/TelegramCore/ProxyServersStatuses.swift b/submodules/TelegramCore/TelegramCore/ProxyServersStatuses.swift new file mode 100644 index 0000000000..3662863252 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ProxyServersStatuses.swift @@ -0,0 +1,137 @@ +import Foundation +#if os(macOS) + import SwiftSignalKitMac + import MtProtoKitMac +#else + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ProxyServerStatus: Equatable { + case checking + case notAvailable + case available(Double) +} + +private final class ProxyServerItemContext { + private var disposable: Disposable? + var value: ProxyServerStatus = .checking + + init(queue: Queue, context: MTContext, datacenterId: Int, server: ProxyServerSettings, updated: @escaping (ProxyServerStatus) -> Void) { + self.disposable = (Signal { subscriber in + let disposable = MTProxyConnectivity.pingProxy(with: context, datacenterId: datacenterId, settings: server.mtProxySettings).start(next: { next in + if let next = next as? MTProxyConnectivityStatus { + if !next.reachable { + subscriber.putNext(.notAvailable) + } else { + subscriber.putNext(.available(next.roundTripTime)) + } + } + }) + + return ActionDisposable { + disposable?.dispose() + } + } |> runOn(queue)).start(next: { status in + updated(status) + }) + } + + deinit { + self.disposable?.dispose() + } +} + +final class ProxyServersStatusesImpl { + private let queue: Queue + + private var contexts: [ProxyServerSettings: ProxyServerItemContext] = [:] + private var serversDisposable: Disposable? + + private var currentValues: [ProxyServerSettings: ProxyServerStatus] = [:] { + didSet { + self.values.set(.single(self.currentValues)) + } + } + let values = Promise<[ProxyServerSettings: ProxyServerStatus]>([:]) + + init(queue: Queue, network: Network, servers: Signal<[ProxyServerSettings], NoError>) { + self.queue = queue + + self.serversDisposable = (servers + |> deliverOn(self.queue)).start(next: { [weak self] servers in + if let strongSelf = self { + let validKeys = Set(servers) + for key in validKeys { + if strongSelf.contexts[key] == nil { + let context = ProxyServerItemContext(queue: strongSelf.queue, context: network.context, datacenterId: network.datacenterId, server: key, updated: { value in + queue.async { + if let strongSelf = self { + strongSelf.contexts[key]?.value = value + strongSelf.updateValues() + } + } + }) + strongSelf.contexts[key] = context + } + } + var removeKeys: [ProxyServerSettings] = [] + for (key, _) in strongSelf.contexts { + if !validKeys.contains(key) { + removeKeys.append(key) + } + } + for key in removeKeys { + let _ = strongSelf.contexts.removeValue(forKey: key) + } + if !removeKeys.isEmpty { + strongSelf.updateValues() + } + } + }) + } + + deinit { + self.serversDisposable?.dispose() + } + + private func updateValues() { + assert(self.queue.isCurrent()) + + var values: [ProxyServerSettings: ProxyServerStatus] = [:] + for (key, context) in self.contexts { + values[key] = context.value + } + self.currentValues = values + } +} + +public final class ProxyServersStatuses { + private let impl: QueueLocalObject + + public init(network: Network, servers: Signal<[ProxyServerSettings], NoError>) { + let queue = Queue() + self.impl = QueueLocalObject(queue: queue, generate: { + return ProxyServersStatusesImpl(queue: queue, network: network, servers: servers) + }) + } + + public func statuses() -> Signal<[ProxyServerSettings: ProxyServerStatus], NoError> { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.values.get().start(next: { value in + subscriber.putNext(value) + })) + } + return ActionDisposable { + self.impl.with({ _ in }) + disposable.dispose() + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ProxySettings.swift b/submodules/TelegramCore/TelegramCore/ProxySettings.swift new file mode 100644 index 0000000000..c88af50c3d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ProxySettings.swift @@ -0,0 +1,189 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum ProxyServerConnection: Equatable, Hashable, PostboxCoding { + case socks5(username: String?, password: String?) + case mtp(secret: Data) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_t", orElse: 0) { + case 0: + self = .socks5(username: decoder.decodeOptionalStringForKey("username"), password: decoder.decodeOptionalStringForKey("password")) + case 1: + self = .mtp(secret: decoder.decodeBytesForKey("secret")?.makeData() ?? Data()) + default: + self = .socks5(username: nil, password: nil) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .socks5(username, password): + encoder.encodeInt32(0, forKey: "_t") + if let username = username { + encoder.encodeString(username, forKey: "username") + } else { + encoder.encodeNil(forKey: "username") + } + if let password = password { + encoder.encodeString(password, forKey: "password") + } else { + encoder.encodeNil(forKey: "password") + } + case let .mtp(secret): + encoder.encodeInt32(1, forKey: "_t") + encoder.encodeBytes(MemoryBuffer(data: secret), forKey: "secret") + } + } + + public var hashValue: Int { + switch self { + case let .socks5(username, password): + var hash = 0 + if let username = username { + hash = hash &* 31 &+ username.hashValue + } + if let password = password { + hash = hash &* 31 &+ password.hashValue + } + return hash + case let .mtp(secret): + return secret.hashValue + } + } +} + +public struct ProxyServerSettings: PostboxCoding, Equatable, Hashable { + public let host: String + public let port: Int32 + public let connection: ProxyServerConnection + + public init(host: String, port: Int32, connection: ProxyServerConnection) { + self.host = host + self.port = port + self.connection = connection + } + + public init(decoder: PostboxDecoder) { + self.host = decoder.decodeStringForKey("host", orElse: "") + self.port = decoder.decodeInt32ForKey("port", orElse: 0) + if let username = decoder.decodeOptionalStringForKey("username") { + self.connection = .socks5(username: username, password: decoder.decodeOptionalStringForKey("password")) + } else { + self.connection = decoder.decodeObjectForKey("connection", decoder: ProxyServerConnection.init(decoder:)) as? ProxyServerConnection ?? ProxyServerConnection.socks5(username: nil, password: nil) + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.host, forKey: "host") + encoder.encodeInt32(self.port, forKey: "port") + encoder.encodeObject(self.connection, forKey: "connection") + } + + public var hashValue: Int { + var hash = self.host.hashValue + hash = hash &* 31 &+ self.port.hashValue + hash = hash &* 31 &+ self.connection.hashValue + return hash + } +} + +public struct ProxySettings: PreferencesEntry, Equatable { + public var enabled: Bool + public var servers: [ProxyServerSettings] + public var activeServer: ProxyServerSettings? + public var useForCalls: Bool + + public static var defaultSettings: ProxySettings { + return ProxySettings(enabled: false, servers: [], activeServer: nil, useForCalls: false) + } + + public init(enabled: Bool, servers: [ProxyServerSettings], activeServer: ProxyServerSettings?, useForCalls: Bool) { + self.enabled = enabled + self.servers = servers + self.activeServer = activeServer + self.useForCalls = useForCalls + } + + public init(decoder: PostboxDecoder) { + if let _ = decoder.decodeOptionalStringForKey("host") { + let legacyServer = ProxyServerSettings(decoder: decoder) + if !legacyServer.host.isEmpty && legacyServer.port != 0 { + self.enabled = true + self.servers = [legacyServer] + } else { + self.enabled = false + self.servers = [] + } + } else { + self.enabled = decoder.decodeInt32ForKey("enabled", orElse: 0) != 0 + self.servers = decoder.decodeObjectArrayWithDecoderForKey("servers") + } + self.activeServer = decoder.decodeObjectForKey("activeServer", decoder: ProxyServerSettings.init(decoder:)) as? ProxyServerSettings + self.useForCalls = decoder.decodeInt32ForKey("useForCalls", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "enabled") + encoder.encodeObjectArray(self.servers, forKey: "servers") + if let activeServer = self.activeServer { + encoder.encodeObject(activeServer, forKey: "activeServer") + } else { + encoder.encodeNil(forKey: "activeServer") + } + encoder.encodeInt32(self.useForCalls ? 1 : 0, forKey: "useForCalls") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? ProxySettings else { + return false + } + + return self == to + } + + public var effectiveActiveServer: ProxyServerSettings? { + if self.enabled, let activeServer = self.activeServer { + return activeServer + } else { + return nil + } + } +} + +public func updateProxySettingsInteractively(accountManager: AccountManager, _ f: @escaping (ProxySettings) -> ProxySettings) -> Signal { + return accountManager.transaction { transaction -> Void in + updateProxySettingsInteractively(transaction: transaction, f) + } +} + +extension ProxyServerSettings { + var mtProxySettings: MTSocksProxySettings { + switch self.connection { + case let .socks5(username, password): + return MTSocksProxySettings(ip: self.host, port: UInt16(clamping: self.port), username: username, password: password, secret: nil) + case let .mtp(secret): + return MTSocksProxySettings(ip: self.host, port: UInt16(clamping: self.port), username: nil, password: nil, secret: secret) + } + } +} + +public func updateProxySettingsInteractively(transaction: AccountManagerModifier, _ f: @escaping (ProxySettings) -> ProxySettings) { + transaction.updateSharedData(SharedDataKeys.proxySettings, { current in + let previous = (current as? ProxySettings) ?? ProxySettings.defaultSettings + let updated = f(previous) + return updated + }) +} diff --git a/submodules/TelegramCore/TelegramCore/Random.swift b/submodules/TelegramCore/TelegramCore/Random.swift new file mode 100644 index 0000000000..20bf912990 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Random.swift @@ -0,0 +1,7 @@ +import Foundation + +public func arc4random64() -> Int64 { + var value: Int64 = 0 + arc4random_buf(&value, 8) + return value +} diff --git a/submodules/TelegramCore/TelegramCore/RateCall.swift b/submodules/TelegramCore/TelegramCore/RateCall.swift new file mode 100644 index 0000000000..0c10328fec --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RateCall.swift @@ -0,0 +1,30 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public func rateCall(account: Account, callId: CallId, starsCount: Int32, comment: String = "", userInitiated: Bool) -> Signal { + var flags: Int32 = 0 + if userInitiated { + flags |= (1 << 0) + } + return account.network.request(Api.functions.phone.setCallRating(flags: flags, peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), rating: starsCount, comment: comment)) + |> retryRequest + |> map { _ in } +} + +public func saveCallDebugLog(account: Account, callId: CallId, log: String) -> Signal { + return account.network.request(Api.functions.phone.saveCallDebug(peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), debug: .dataJSON(data: log))) + |> retryRequest + |> map { _ in } +} diff --git a/submodules/TelegramCore/TelegramCore/Reachability.h b/submodules/TelegramCore/TelegramCore/Reachability.h new file mode 100644 index 0000000000..c24384906c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Reachability.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + */ + +#import +#import +#import + + +typedef enum : NSInteger { + NotReachable = 0, + ReachableViaWiFi, + ReachableViaWWAN +} NetworkStatus; + +#pragma mark IPv6 Support +//Reachability fully support IPv6. For full details, see ReadMe.md. + + +extern NSString *kReachabilityChangedNotification; + + +@interface Reachability : NSObject + +@property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status); + +/*! + * Use to check the reachability of a given host name. + */ ++ (instancetype)reachabilityWithHostName:(NSString *)hostName; + +/*! + * Use to check the reachability of a given IP address. + */ ++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress; + +/*! + * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. + */ ++ (instancetype)reachabilityForInternetConnection; + + +#pragma mark reachabilityForLocalWiFi +//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. +//+ (instancetype)reachabilityForLocalWiFi; + +/*! + * Start listening for reachability notifications on the current run loop. + */ +- (BOOL)startNotifier; +- (void)stopNotifier; + +- (NetworkStatus)currentReachabilityStatus; + +/*! + * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. + */ +- (BOOL)connectionRequired; + +@end + + diff --git a/submodules/TelegramCore/TelegramCore/Reachability.m b/submodules/TelegramCore/TelegramCore/Reachability.m new file mode 100644 index 0000000000..be67002fa3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Reachability.m @@ -0,0 +1,357 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + */ + +#import +#import +#import +#import +#import + +#import + +#import "Reachability.h" + +#import +#import + +#pragma mark IPv6 Support +//Reachability fully support IPv6. For full details, see ReadMe.md. + + +NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification"; + + +#pragma mark - Supporting functions + +#define kShouldPrintReachabilityFlags 0 + +static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) +{ +#if kShouldPrintReachabilityFlags + + NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", +#if TARGET_OS_IPHONE + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-' +#else + '-' +#endif + , + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', + comment + ); +#endif +} + +@interface ReachabilityAtomic : NSObject +{ + pthread_mutex_t _lock; + pthread_mutexattr_t _attr; + id _value; +} + +@end + +@implementation ReachabilityAtomic + +- (instancetype)initWithValue:(id)value { + self = [super init]; + if (self != nil) { + pthread_mutex_init(&_lock, NULL); + _value = value; + } + return self; +} + +- (void)dealloc { + pthread_mutex_destroy(&_lock); +} + +- (id)swap:(id)newValue { + id previousValue = nil; + pthread_mutex_lock(&_lock); + previousValue = _value; + _value = newValue; + pthread_mutex_unlock(&_lock); + return previousValue; +} + +- (id)value { + id previousValue = nil; + pthread_mutex_lock(&_lock); + previousValue = _value; + pthread_mutex_unlock(&_lock); + + return previousValue; +} + +- (id)modify:(id (^)(id))f { + id newValue = nil; + pthread_mutex_lock(&_lock); + newValue = f(_value); + _value = newValue; + pthread_mutex_unlock(&_lock); + return newValue; +} + +- (id)with:(id (^)(id))f { + id result = nil; + pthread_mutex_lock(&_lock); + result = f(_value); + pthread_mutex_unlock(&_lock); + return result; +} + +@end + +static int32_t nextKey = 1; +static ReachabilityAtomic *contexts() { + static ReachabilityAtomic *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[ReachabilityAtomic alloc] initWithValue:@{}]; + }); + return instance; +} + +static void withContext(int32_t key, void (^f)(Reachability *)) { + Reachability *reachability = [contexts() with:^id(NSDictionary *dict) { + return dict[@(key)]; + }]; + f(reachability); +} + +static int32_t addContext(Reachability *context) { + int32_t key = OSAtomicIncrement32(&nextKey); + [contexts() modify:^id(NSMutableDictionary *dict) { + NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict]; + updatedDict[@(key)] = context; + return updatedDict; + }]; + return key; +} + +static void removeContext(int32_t key) { + [contexts() modify:^id(NSMutableDictionary *dict) { + NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict]; + [updatedDict removeObjectForKey:@(key)]; + return updatedDict; + }]; +} + +static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ +#pragma unused (target, flags) + //NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); + //NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); + + int32_t key = (int32_t)((intptr_t)info); + withContext(key, ^(Reachability *context) { + if ([context isKindOfClass:[Reachability class]] && context.reachabilityChanged != nil) + context.reachabilityChanged(context.currentReachabilityStatus); + }); +} + + +#pragma mark - Reachability implementation + +@implementation Reachability +{ + int32_t _key; + SCNetworkReachabilityRef _reachabilityRef; +} + ++ (instancetype)reachabilityWithHostName:(NSString *)hostName +{ + Reachability* returnValue = NULL; + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); + if (reachability != NULL) + { + returnValue= [[self alloc] init]; + if (returnValue != NULL) + { + returnValue->_reachabilityRef = reachability; + } + else { + CFRelease(reachability); + } + } + if (returnValue) { + returnValue->_key = addContext(returnValue); + } + return returnValue; +} + + ++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress +{ + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress); + + Reachability* returnValue = NULL; + + if (reachability != NULL) + { + returnValue = [[self alloc] init]; + if (returnValue != NULL) + { + returnValue->_reachabilityRef = reachability; + } + else { + CFRelease(reachability); + } + } + if (returnValue) { + returnValue->_key = addContext(returnValue); + } + return returnValue; +} + + ++ (instancetype)reachabilityForInternetConnection +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]; +} + +#pragma mark reachabilityForLocalWiFi +//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. +//+ (instancetype)reachabilityForLocalWiFi + + + +#pragma mark - Start and stop notifier + +- (BOOL)startNotifier +{ + BOOL returnValue = NO; + SCNetworkReachabilityContext context = {0, (void *)((intptr_t)_key), NULL, NULL, NULL}; + + if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) + { + if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { + returnValue = YES; + } + } + + return returnValue; +} + + +- (void)stopNotifier +{ + if (_reachabilityRef != NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + } +} + + +- (void)dealloc +{ + removeContext(_key); + [self stopNotifier]; + if (_reachabilityRef != NULL) + { + CFRelease(_reachabilityRef); + } +} + + +#pragma mark - Network Flag Handling + +- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags +{ + PrintReachabilityFlags(flags, "networkStatusForFlags"); + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) + { + // The target host is not reachable. + return NotReachable; + } + + NetworkStatus returnValue = NotReachable; + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) + { + /* + If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi... + */ + returnValue = ReachableViaWiFi; + } + + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) + { + /* + ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs... + */ + + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) + { + /* + ... and no [user] intervention is needed... + */ + returnValue = ReachableViaWiFi; + } + } + +#if TARGET_OS_IPHONE + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) + { + /* + ... but WWAN connections are OK if the calling application is using the CFNetwork APIs. + */ + returnValue = ReachableViaWWAN; + } +#endif + + return returnValue; +} + + +- (BOOL)connectionRequired +{ + NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + + return NO; +} + + +- (NetworkStatus)currentReachabilityStatus +{ + NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef"); + NetworkStatus returnValue = NotReachable; + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) + { + returnValue = [self networkStatusForFlags:flags]; + } + + return returnValue; +} + + +@end diff --git a/submodules/TelegramCore/TelegramCore/RecentAccountSession.swift b/submodules/TelegramCore/TelegramCore/RecentAccountSession.swift new file mode 100644 index 0000000000..5e2e299be0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentAccountSession.swift @@ -0,0 +1,95 @@ +import Foundation + +public struct AccountSessionFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let isOfficial = AccountSessionFlags(rawValue: (1 << 1)) + public static let passwordPending = AccountSessionFlags(rawValue: (1 << 2)) +} + +public struct RecentAccountSession: Equatable { + public let hash: Int64 + public let deviceModel: String + public let platform: String + public let systemVersion: String + public let apiId: Int32 + public let appName: String + public let appVersion: String + public let creationDate: Int32 + public let activityDate: Int32 + public let ip: String + public let country: String + public let region: String + public let flags: AccountSessionFlags + + public var isCurrent: Bool { + return self.hash == 0 + } + + public static func ==(lhs: RecentAccountSession, rhs: RecentAccountSession) -> Bool { + if lhs.hash != rhs.hash { + return false + } + if lhs.deviceModel != rhs.deviceModel { + return false + } + if lhs.platform != rhs.platform { + return false + } + if lhs.systemVersion != rhs.systemVersion { + return false + } + if lhs.apiId != rhs.apiId { + return false + } + if lhs.appName != rhs.appName { + return false + } + if lhs.appVersion != rhs.appVersion { + return false + } + if lhs.creationDate != rhs.creationDate { + return false + } + if lhs.activityDate != rhs.activityDate { + return false + } + if lhs.ip != rhs.ip { + return false + } + if lhs.country != rhs.country { + return false + } + if lhs.region != rhs.region { + return false + } + if lhs.flags != rhs.flags { + return false + } + return true + } +} + +extension RecentAccountSession { + init(apiAuthorization: Api.Authorization) { + switch apiAuthorization { + case let .authorization(flags, hash, deviceModel, platform, systemVersion, apiId, appName, appVersion, dateCreated, dateActive, ip, country, region): + var accountSessionFlags: AccountSessionFlags = [] + if (flags & (1 << 1)) != 0 { + accountSessionFlags.insert(.isOfficial) + } + if (flags & (1 << 2)) != 0 { + accountSessionFlags.insert(.passwordPending) + } + self.init(hash: hash, deviceModel: deviceModel, platform: platform, systemVersion: systemVersion, apiId: apiId, appName: appName, appVersion: appVersion, creationDate: dateCreated, activityDate: dateActive, ip: ip, country: country, region: region, flags: accountSessionFlags) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RecentAccountSessions.swift b/submodules/TelegramCore/TelegramCore/RecentAccountSessions.swift new file mode 100644 index 0000000000..bb9e74acf8 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentAccountSessions.swift @@ -0,0 +1,49 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func requestRecentAccountSessions(account: Account) -> Signal<[RecentAccountSession], NoError> { + return account.network.request(Api.functions.account.getAuthorizations()) + |> retryRequest + |> map { result -> [RecentAccountSession] in + var sessions: [RecentAccountSession] = [] + switch result { + case let .authorizations(authorizations): + for authorization in authorizations { + sessions.append(RecentAccountSession(apiAuthorization: authorization)) + } + } + return sessions + } +} + +public enum TerminateSessionError { + case generic + case freshReset +} + +public func terminateAccountSession(account: Account, hash: Int64) -> Signal { + return account.network.request(Api.functions.account.resetAuthorization(hash: hash)) + |> mapError { error -> TerminateSessionError in + if error.errorCode == 406 { + return .freshReset + } + return .generic + } + |> mapToSignal { _ -> Signal in + return .single(Void()) + } +} + +public func terminateOtherAccountSessions(account: Account) -> Signal { + return account.network.request(Api.functions.auth.resetAuthorizations()) + |> retryRequest + |> mapToSignal { _ -> Signal in + return .single(Void()) + } +} diff --git a/submodules/TelegramCore/TelegramCore/RecentMediaItem.swift b/submodules/TelegramCore/TelegramCore/RecentMediaItem.swift new file mode 100644 index 0000000000..30bd5cc1b6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentMediaItem.swift @@ -0,0 +1,50 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct RecentMediaItemId { + public let rawValue: MemoryBuffer + public let mediaId: MediaId + + init(_ rawValue: MemoryBuffer) { + self.rawValue = rawValue + assert(rawValue.length == 4 + 8) + var mediaIdNamespace: Int32 = 0 + var mediaIdId: Int64 = 0 + memcpy(&mediaIdNamespace, rawValue.memory, 4) + memcpy(&mediaIdId, rawValue.memory.advanced(by: 4), 8) + self.mediaId = MediaId(namespace: mediaIdNamespace, id: mediaIdId) + } + + public init(_ mediaId: MediaId) { + self.mediaId = mediaId + var mediaIdNamespace: Int32 = mediaId.namespace + var mediaIdId: Int64 = mediaId.id + self.rawValue = MemoryBuffer(memory: malloc(4 + 8)!, capacity: 4 + 8, length: 4 + 8, freeWhenDone: true) + memcpy(self.rawValue.memory, &mediaIdNamespace, 4) + memcpy(self.rawValue.memory.advanced(by: 4), &mediaIdId, 8) + } +} + +public final class RecentMediaItem: OrderedItemListEntryContents, Equatable { + public let media: Media + + init(_ media: Media) { + self.media = media + } + + public init(decoder: PostboxDecoder) { + self.media = decoder.decodeObjectForKey("m") as! Media + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.media, forKey: "m") + } + + public static func ==(lhs: RecentMediaItem, rhs: RecentMediaItem) -> Bool { + return lhs.media.isEqual(to: rhs.media) + } +} diff --git a/submodules/TelegramCore/TelegramCore/RecentPeerItem.swift b/submodules/TelegramCore/TelegramCore/RecentPeerItem.swift new file mode 100644 index 0000000000..176bf92a70 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentPeerItem.swift @@ -0,0 +1,42 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct RecentPeerItemId { + public let rawValue: MemoryBuffer + public let peerId: PeerId + + init(_ rawValue: MemoryBuffer) { + self.rawValue = rawValue + assert(rawValue.length == 8) + var idValue: Int64 = 0 + memcpy(&idValue, rawValue.memory, 8) + self.peerId = PeerId(idValue) + } + + init(_ peerId: PeerId) { + self.peerId = peerId + var idValue: Int64 = peerId.toInt64() + self.rawValue = MemoryBuffer(memory: malloc(8)!, capacity: 8, length: 8, freeWhenDone: true) + memcpy(self.rawValue.memory, &idValue, 8) + } +} + +public final class RecentPeerItem: OrderedItemListEntryContents { + public let rating: Double + + init(rating: Double) { + self.rating = rating + } + + public init(decoder: PostboxDecoder) { + self.rating = decoder.decodeDoubleForKey("r", orElse: 0.0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeDouble(self.rating, forKey: "r") + } +} diff --git a/submodules/TelegramCore/TelegramCore/RecentPeers.swift b/submodules/TelegramCore/TelegramCore/RecentPeers.swift new file mode 100644 index 0000000000..5f4af9ae72 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentPeers.swift @@ -0,0 +1,260 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum RecentPeers { + case peers([Peer]) + case disabled +} + +final class CachedRecentPeers: PostboxCoding { + let enabled: Bool + let ids: [PeerId] + + init(enabled: Bool, ids: [PeerId]) { + self.enabled = enabled + self.ids = ids + } + + init(decoder: PostboxDecoder) { + self.enabled = decoder.decodeInt32ForKey("enabled", orElse: 0) != 0 + self.ids = decoder.decodeInt64ArrayForKey("ids").map(PeerId.init) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "enabled") + encoder.encodeInt64Array(self.ids.map({ $0.toInt64() }), forKey: "ids") + } + + static func cacheKey() -> ValueBoxKey { + let key = ValueBoxKey(length: 0) + return key + } +} + +private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1) + +private func cachedRecentPeersEntryId() -> ItemCacheEntryId { + return ItemCacheEntryId(collectionId: 101, key: CachedRecentPeers.cacheKey()) +} + +public func recentPeers(account: Account) -> Signal { + let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId()) + return account.postbox.combinedView(keys: [key]) + |> mapToSignal { views -> Signal in + if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers { + if value.enabled { + return account.postbox.multiplePeersView(value.ids) + |> map { view -> RecentPeers in + var peers: [Peer] = [] + for id in value.ids { + if let peer = view.peers[id], id != account.peerId { + peers.append(peer) + } + } + return .peers(peers) + } + } else { + return .single(.disabled) + } + } else { + return .single(.peers([])) + } + } +} + +public func managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox, network: Network) -> Signal { + let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId()) + let peersEnabled = postbox.combinedView(keys: [key]) + |> map { views -> Bool in + if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers { + return value.enabled + } else { + return true + } + } + |> distinctUntilChanged + + let updateOnce = + network.request(Api.functions.contacts.getTopPeers(flags: 1 << 0, offset: 0, limit: 50, hash: 0)) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + switch result { + case let .topPeers(_, _, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + updatePeers(transaction: transaction, peers: peers, update: { return $1 }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: peers.map { $0.id }), collectionSpec: collectionSpec) + case .topPeersNotModified: + break + case .topPeersDisabled: + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec) + } + } + } + + return peersEnabled |> mapToSignal { _ -> Signal in + return updateOnce + } +} + +public func removeRecentPeer(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers else { + return .complete() + } + + if let index = entry.ids.index(of: peerId) { + var updatedIds = entry.ids + updatedIds.remove(at: index) + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: entry.enabled, ids: updatedIds), collectionSpec: collectionSpec) + } + if let peer = transaction.getPeer(peerId), let apiPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.contacts.resetTopPeerRating(category: .topPeerCategoryCorrespondents, peer: apiPeer)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} + +public func updateRecentPeersEnabled(postbox: Postbox, network: Network, enabled: Bool) -> Signal { + return postbox.transaction { transaction -> Signal in + var currentValue = true + if let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers { + currentValue = entry.enabled + } + + if currentValue == enabled { + return .complete() + } + + return network.request(Api.functions.contacts.toggleTopPeers(enabled: enabled ? .boolTrue : .boolFalse)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return postbox.transaction { transaction -> Void in + if !enabled { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec) + } else { + let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: entry?.ids ?? []), collectionSpec: collectionSpec) + } + } + } + } |> switchToLatest +} + +public func managedRecentlyUsedInlineBots(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal { + let remotePeers = network.request(Api.functions.contacts.getTopPeers(flags: 1 << 2, offset: 0, limit: 16, hash: 0)) + |> retryRequest + |> map { result -> ([Peer], [PeerId: PeerPresence], [(PeerId, Double)])? in + switch result { + case .topPeersDisabled: + break + case let .topPeers(categories, _, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + var peersWithRating: [(PeerId, Double)] = [] + for category in categories { + switch category { + case let .topPeerCategoryPeers(_, _, topPeers): + for topPeer in topPeers { + switch topPeer { + case let .topPeer(apiPeer, rating): + peersWithRating.append((apiPeer.peerId, rating)) + } + } + } + } + return (peers, peerPresences, peersWithRating) + case .topPeersNotModified: + break + } + return ([], [:], []) + } + + let updatedRemotePeers = remotePeers + |> mapToSignal { peersAndPresences -> Signal in + if let (peers, peerPresences, peersWithRating) = peersAndPresences { + return postbox.transaction { transaction -> Void in + updatePeers(transaction: transaction, peers: peers, update: { return $1 }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + let sortedPeersWithRating = peersWithRating.sorted(by: { $0.1 > $1.1 }) + + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, items: sortedPeersWithRating.map { (peerId, rating) in + return OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: rating)) + }) + } + } else { + return .complete() + } + } + + return updatedRemotePeers +} + +public func addRecentlyUsedInlineBot(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> Void in + var maxRating = 1.0 + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots) { + if let contents = entry.contents as? RecentPeerItem { + maxRating = max(maxRating, contents.rating) + } + } + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: maxRating)), removeTailIfCountExceeds: 20) + } +} + +public func recentlyUsedInlineBots(postbox: Postbox) -> Signal<[(Peer, Double)], NoError> { + return postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.CloudRecentInlineBots)]) + |> take(1) + |> mapToSignal { view -> Signal<[(Peer, Double)], NoError> in + return postbox.transaction { transaction -> [(Peer, Double)] in + var peers: [(Peer, Double)] = [] + if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudRecentInlineBots)] as? OrderedItemListView { + for item in view.items { + let peerId = RecentPeerItemId(item.id).peerId + if let peer = transaction.getPeer(peerId), let contents = item.contents as? RecentPeerItem { + peers.append((peer, contents.rating)) + } + } + } + return peers + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/RecentWebSessions.swift b/submodules/TelegramCore/TelegramCore/RecentWebSessions.swift new file mode 100644 index 0000000000..dda450af43 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentWebSessions.swift @@ -0,0 +1,71 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct WebAuthorization : Equatable { + public let hash: Int64 + public let botId: PeerId + public let domain: String + public let browser: String + public let platform: String + public let dateCreated: Int32 + public let dateActive: Int32 + public let ip: String + public let region: String + + public static func ==(lhs: WebAuthorization, rhs: WebAuthorization) -> Bool { + return lhs.hash == rhs.hash && lhs.botId == rhs.botId && lhs.domain == rhs.domain && lhs.browser == rhs.browser && lhs.platform == rhs.platform && lhs.dateActive == rhs.dateActive && lhs.dateCreated == rhs.dateCreated && lhs.ip == rhs.ip && lhs.region == rhs.region + } +} + +public func webSessions(network: Network) -> Signal<([WebAuthorization], [PeerId: Peer]), NoError> { + return network.request(Api.functions.account.getWebAuthorizations()) + |> retryRequest + |> map { result -> ([WebAuthorization], [PeerId : Peer]) in + var sessions: [WebAuthorization] = [] + var peers:[PeerId : Peer] = [:] + switch result { + case let .webAuthorizations(authorizations, users): + for authorization in authorizations { + switch authorization { + case let .webAuthorization(hash, botId, domain, browser, platform, dateCreated, dateActive, ip, region): + sessions.append(WebAuthorization(hash: hash, botId: PeerId(namespace: Namespaces.Peer.CloudUser, id: botId), domain: domain, browser: browser, platform: platform, dateCreated: dateCreated, dateActive: dateActive, ip: ip, region: region)) + + } + } + for user in users { + let peer = TelegramUser(user: user) + peers[peer.id] = peer + } + } + return (sessions, peers) + } +} + + +public func terminateWebSession(network: Network, hash: Int64) -> Signal { + return network.request(Api.functions.account.resetWebAuthorization(hash: hash)) + |> retryRequest + |> map { result in + switch result { + case .boolFalse: + return false + case .boolTrue: + return true + } + } +} + + + +public func terminateAllWebSessions(network: Network) -> Signal { + return network.request(Api.functions.account.resetWebAuthorizations()) + |> retryRequest + |> map { _ in } +} + diff --git a/submodules/TelegramCore/TelegramCore/RecentlySearchedPeerIds.swift b/submodules/TelegramCore/TelegramCore/RecentlySearchedPeerIds.swift new file mode 100644 index 0000000000..8161f39563 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentlySearchedPeerIds.swift @@ -0,0 +1,99 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func addRecentlySearchedPeer(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: 0.0)), removeTailIfCountExceeds: 20) + } +} + +public func removeRecentlySearchedPeer(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, itemId: RecentPeerItemId(peerId).rawValue) + } +} + +public func clearRecentlySearchedPeers(postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, items: []) + } +} + +public struct RecentlySearchedPeerSubpeerSummary: Equatable { + public let count: Int +} + +public struct RecentlySearchedPeer: Equatable { + public let peer: RenderedPeer + public let presence: TelegramUserPresence? + public let notificationSettings: TelegramPeerNotificationSettings? + public let unreadCount: Int32 + public let subpeerSummary: RecentlySearchedPeerSubpeerSummary? +} + +public func recentlySearchedPeers(postbox: Postbox) -> Signal<[RecentlySearchedPeer], NoError> { + return postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.RecentlySearchedPeerIds)]) + |> mapToSignal { view -> Signal<[RecentlySearchedPeer], NoError> in + var peerIds: [PeerId] = [] + if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.RecentlySearchedPeerIds)] as? OrderedItemListView { + for item in view.items { + let peerId = RecentPeerItemId(item.id).peerId + peerIds.append(peerId) + } + } + var keys: [PostboxViewKey] = [] + let unreadCountsKey: PostboxViewKey = .unreadCounts(items: peerIds.map(UnreadMessageCountsItem.peer)) + keys.append(unreadCountsKey) + keys.append(contentsOf: peerIds.map({ .peer(peerId: $0, components: .all) })) + + return postbox.combinedView(keys: keys) + |> map { view -> [RecentlySearchedPeer] in + var result: [RecentlySearchedPeer] = [] + var unreadCounts: [PeerId: Int32] = [:] + if let unreadCountsView = view.views[unreadCountsKey] as? UnreadMessageCountsView { + for entry in unreadCountsView.entries { + if case let .peer(peerId, state) = entry { + unreadCounts[peerId] = state?.count ?? 0 + } + } + } + + for peerId in peerIds { + if let peerView = view.views[.peer(peerId: peerId, components: .all)] as? PeerView { + var presence: TelegramUserPresence? + var unreadCount = unreadCounts[peerId] ?? 0 + if let peer = peerView.peers[peerId] { + if let associatedPeerId = peer.associatedPeerId { + presence = peerView.peerPresences[associatedPeerId] as? TelegramUserPresence + } else { + presence = peerView.peerPresences[peerId] as? TelegramUserPresence + } + + if let channel = peer as? TelegramChannel { + if case .member = channel.participationStatus { + } else { + unreadCount = 0 + } + } + } + + var subpeerSummary: RecentlySearchedPeerSubpeerSummary? + if let cachedData = peerView.cachedData as? CachedChannelData { + let count: Int32 = cachedData.participantsSummary.memberCount ?? 0 + subpeerSummary = RecentlySearchedPeerSubpeerSummary(count: Int(count)) + } + + result.append(RecentlySearchedPeer(peer: RenderedPeer(peerId: peerId, peers: SimpleDictionary(peerView.peers)), presence: presence, notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, unreadCount: unreadCount, subpeerSummary: subpeerSummary)) + } + } + + return result + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RecentlyUsedHashtags.swift b/submodules/TelegramCore/TelegramCore/RecentlyUsedHashtags.swift new file mode 100644 index 0000000000..4e21bf102c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RecentlyUsedHashtags.swift @@ -0,0 +1,70 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private struct RecentHashtagItemId { + public let rawValue: MemoryBuffer + + var value: String { + return String(data: self.rawValue.makeData(), encoding: .utf8) ?? "" + } + + init(_ rawValue: MemoryBuffer) { + self.rawValue = rawValue + } + + init?(_ value: String) { + if let data = value.data(using: .utf8) { + self.rawValue = MemoryBuffer(data: data) + } else { + return nil + } + } +} + +final class RecentHashtagItem: OrderedItemListEntryContents { + init() { + } + + public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } +} + +func addRecentlyUsedHashtag(transaction: Transaction, string: String) { + if let itemId = RecentHashtagItemId(string) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentHashtagItem()), removeTailIfCountExceeds: 100) + } +} + +public func removeRecentlyUsedHashtag(postbox: Postbox, string: String) -> Signal { + return postbox.transaction { transaction -> Void in + if let itemId = RecentHashtagItemId(string) { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, itemId: itemId.rawValue) + } + } +} + +public func recentlyUsedHashtags(postbox: Postbox) -> Signal<[String], NoError> { + return postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.RecentlyUsedHashtags)]) + |> mapToSignal { view -> Signal<[String], NoError> in + return postbox.transaction { transaction -> [String] in + var result: [String] = [] + if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.RecentlyUsedHashtags)] as? OrderedItemListView { + for item in view.items { + let value = RecentHashtagItemId(item.id).value + result.append(value) + } + } + return result + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/Regex.swift b/submodules/TelegramCore/TelegramCore/Regex.swift new file mode 100644 index 0000000000..474e383e1f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Regex.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct Regex { + let pattern: String + let options: NSRegularExpression.Options! + + private var matcher: NSRegularExpression { + return try! NSRegularExpression(pattern: self.pattern, options: self.options) + } + + public init(_ pattern: String) { + self.pattern = pattern + self.options = [] + } + + public func match(_ string: String, options: NSRegularExpression.MatchingOptions = []) -> Bool { + return self.matcher.numberOfMatches(in: string, options: options, range: NSMakeRange(0, string.utf16.count)) != 0 + } +} + +public protocol RegularExpressionMatchable { + func match(_ regex: Regex) -> Bool +} + +extension String: RegularExpressionMatchable { + public func match(_ regex: Regex) -> Bool { + return regex.match(self) + } +} + +public func ~=(pattern: Regex, matchable: T) -> Bool { + return matchable.match(pattern) +} diff --git a/submodules/TelegramCore/TelegramCore/RegisterNotificationToken.swift b/submodules/TelegramCore/TelegramCore/RegisterNotificationToken.swift new file mode 100644 index 0000000000..7b7fe56306 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RegisterNotificationToken.swift @@ -0,0 +1,47 @@ +import Foundation +#if os(macOS) +import SwiftSignalKitMac +import PostboxMac +#else +import SwiftSignalKit +import Postbox +#endif + +public enum NotificationTokenType { + case aps(encrypt: Bool) + case voip +} + +public func unregisterNotificationToken(account: Account, token: Data, type: NotificationTokenType, otherAccountUserIds: [Int32]) -> Signal { + let mappedType: Int32 + switch type { + case .aps: + mappedType = 1 + case .voip: + mappedType = 9 + } + return account.network.request(Api.functions.account.unregisterDevice(tokenType: mappedType, token: hexString(token), otherUids: otherAccountUserIds)) + |> retryRequest + |> ignoreValues +} + +public func registerNotificationToken(account: Account, token: Data, type: NotificationTokenType, sandbox: Bool, otherAccountUserIds: [Int32]) -> Signal { + return masterNotificationsKey(account: account, ignoreDisabled: false) + |> mapToSignal { masterKey -> Signal in + let mappedType: Int32 + var keyData = Data() + switch type { + case let .aps(encrypt): + mappedType = 1 + if encrypt { + keyData = masterKey.data + } + case .voip: + mappedType = 9 + keyData = masterKey.data + } + return account.network.request(Api.functions.account.registerDevice(tokenType: mappedType, token: hexString(token), appSandbox: sandbox ? .boolTrue : .boolFalse, secret: Buffer(data: keyData), otherUids: otherAccountUserIds)) + |> retryRequest + |> ignoreValues + } +} diff --git a/submodules/TelegramCore/TelegramCore/RegularChatState.swift b/submodules/TelegramCore/TelegramCore/RegularChatState.swift new file mode 100644 index 0000000000..4d2ebea322 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RegularChatState.swift @@ -0,0 +1,41 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +final class RegularChatState: PeerChatState, Equatable { + let invalidatedPts: Int32? + + init(invalidatedPts: Int32?) { + self.invalidatedPts = invalidatedPts + } + + init(decoder: PostboxDecoder) { + self.invalidatedPts = decoder.decodeOptionalInt32ForKey("ipts") + } + + func encode(_ encoder: PostboxEncoder) { + if let invalidatedPts = self.invalidatedPts { + encoder.encodeInt32(invalidatedPts, forKey: "ipts") + } else { + encoder.encodeNil(forKey: "ipts") + } + } + + func withUpdatedInvalidatedPts(_ invalidatedPts: Int32?) -> RegularChatState { + return RegularChatState(invalidatedPts: invalidatedPts) + } + + func equals(_ other: PeerChatState) -> Bool { + if let other = other as? RegularChatState, other == self { + return true + } + return false + } + + static func ==(lhs: RegularChatState, rhs: RegularChatState) -> Bool { + return lhs.invalidatedPts == rhs.invalidatedPts + } +} diff --git a/submodules/TelegramCore/TelegramCore/RemoteStorageConfiguration.swift b/submodules/TelegramCore/TelegramCore/RemoteStorageConfiguration.swift new file mode 100644 index 0000000000..63b3210a50 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RemoteStorageConfiguration.swift @@ -0,0 +1,57 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public final class RemoteStorageConfiguration: PreferencesEntry { + public let webDocumentsHostDatacenterId: Int32 + + init(webDocumentsHostDatacenterId: Int32) { + self.webDocumentsHostDatacenterId = webDocumentsHostDatacenterId + } + + public init(decoder: PostboxDecoder) { + self.webDocumentsHostDatacenterId = decoder.decodeInt32ForKey("webDocumentsHostDatacenterId", orElse: 4) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.webDocumentsHostDatacenterId, forKey: "webDocumentsHostDatacenterId") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? RemoteStorageConfiguration else { + return false + } + if self.webDocumentsHostDatacenterId != to.webDocumentsHostDatacenterId { + return false + } + return true + } +} + +public func currentWebDocumentsHostDatacenterId(postbox: Postbox, isTestingEnvironment: Bool) -> Signal { + return postbox.transaction { transaction -> Int32 in + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration) as? RemoteStorageConfiguration { + return entry.webDocumentsHostDatacenterId + } else { + if isTestingEnvironment { + return 2 + } else { + return 4 + } + } + } +} + +func updateRemoteStorageConfiguration(transaction: Transaction, configuration: RemoteStorageConfiguration) { + let current = transaction.getPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration) as? RemoteStorageConfiguration + if let current = current, current.isEqual(to: configuration) { + return + } + + transaction.setPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration, value: configuration) +} diff --git a/submodules/TelegramCore/TelegramCore/RemovePeerChat.swift b/submodules/TelegramCore/TelegramCore/RemovePeerChat.swift new file mode 100644 index 0000000000..b91778ae2f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RemovePeerChat.swift @@ -0,0 +1,55 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func removePeerChat(account: Account, peerId: PeerId, reportChatSpam: Bool, deleteGloballyIfPossible: Bool = false) -> Signal { + return account.postbox.transaction { transaction -> Void in + removePeerChat(account: account, transaction: transaction, mediaBox: account.postbox.mediaBox, peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible) + } +} + +public func removePeerChat(account: Account, transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, reportChatSpam: Bool, deleteGloballyIfPossible: Bool) { + if let _ = transaction.getPeerChatInterfaceState(peerId) { + transaction.updatePeerChatInterfaceState(peerId, update: { current in + if let current = current { + return account.auxiliaryMethods.updatePeerChatInputState(current, nil) + } else { + return nil + } + }) + } + if peerId.namespace == Namespaces.Peer.SecretChat { + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.terminate(reportSpam: reportChatSpam), state: state).withUpdatedEmbeddedState(.terminated) + if updatedState != state { + transaction.setPeerChatState(peerId, state: updatedState) + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + updatePeers(transaction: transaction, peers: [peer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in + return updated + }) + } + } + } + clearHistory(transaction: transaction, mediaBox: mediaBox, peerId: peerId) + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, itemId: RecentPeerItemId(peerId).rawValue) + } else { + cloudChatAddRemoveChatOperation(transaction: transaction, peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible) + if peerId.namespace == Namespaces.Peer.CloudUser { + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + clearHistory(transaction: transaction, mediaBox: mediaBox, peerId: peerId) + } else if peerId.namespace == Namespaces.Peer.CloudGroup { + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + clearHistory(transaction: transaction, mediaBox: mediaBox, peerId: peerId) + } else { + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + } + } + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, itemId: RecentPeerItemId(peerId).rawValue) +} diff --git a/submodules/TelegramCore/TelegramCore/RemovePeerMember.swift b/submodules/TelegramCore/TelegramCore/RemovePeerMember.swift new file mode 100644 index 0000000000..e8eeb7793f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RemovePeerMember.swift @@ -0,0 +1,62 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func removePeerMember(account: Account, peerId: PeerId, memberId: PeerId) -> Signal { + if peerId.namespace == Namespaces.Peer.CloudChannel { + return updateChannelMemberBannedRights(account: account, peerId: peerId, memberId: memberId, rights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: 0)) + |> mapToSignal { _ -> Signal in + return .complete() + } + } + + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { + if let group = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.deleteChatUser(chatId: group.id.id, userId: inputUser)) + |> mapError { error -> Void in + return Void() + } + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedGroupData, let participants = cachedData.participants { + var updatedParticipants = participants.participants + for i in 0 ..< participants.participants.count { + if participants.participants[i].peerId == memberId { + updatedParticipants.remove(at: i) + break + } + } + + return cachedData.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version)) + } else { + return cachedData + } + }) + } + } + } else { + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ReplyMarkupMessageAttribute.swift new file mode 100644 index 0000000000..fef8e814e3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ReplyMarkupMessageAttribute.swift @@ -0,0 +1,241 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum ReplyMarkupButtonAction: PostboxCoding, Equatable { + case text + case url(String) + case callback(MemoryBuffer) + case requestPhone + case requestMap + case switchInline(samePeer: Bool, query: String) + case openWebApp + case payment + case urlAuth(url: String, buttonId: Int32) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case 0: + self = .text + case 1: + self = .url(decoder.decodeStringForKey("u", orElse: "")) + case 2: + self = .callback(decoder.decodeBytesForKey("d") ?? MemoryBuffer()) + case 3: + self = .requestPhone + case 4: + self = .requestMap + case 5: + self = .switchInline(samePeer: decoder.decodeInt32ForKey("s", orElse: 0) != 0, query: decoder.decodeStringForKey("q", orElse: "")) + case 6: + self = .openWebApp + case 7: + self = .payment + case 8: + self = .urlAuth(url: decoder.decodeStringForKey("u", orElse: ""), buttonId: decoder.decodeInt32ForKey("b", orElse: 0)) + default: + self = .text + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .text: + encoder.encodeInt32(0, forKey: "v") + case let .url(url): + encoder.encodeInt32(1, forKey: "v") + encoder.encodeString(url, forKey: "u") + case let .callback(data): + encoder.encodeInt32(2, forKey: "v") + encoder.encodeBytes(data, forKey: "d") + case .requestPhone: + encoder.encodeInt32(3, forKey: "v") + case .requestMap: + encoder.encodeInt32(4, forKey: "v") + case let .switchInline(samePeer, query): + encoder.encodeInt32(5, forKey: "v") + encoder.encodeInt32(samePeer ? 1 : 0, forKey: "s") + encoder.encodeString(query, forKey: "q") + case .openWebApp: + encoder.encodeInt32(6, forKey: "v") + case .payment: + encoder.encodeInt32(7, forKey: "v") + case let .urlAuth(url, buttonId): + encoder.encodeInt32(8, forKey: "v") + encoder.encodeString(url, forKey: "u") + encoder.encodeInt32(buttonId, forKey: "b") + } + } +} + +public struct ReplyMarkupButton: PostboxCoding, Equatable { + public let title: String + public let titleWhenForwarded: String? + public let action: ReplyMarkupButtonAction + + init(title: String, titleWhenForwarded: String?, action: ReplyMarkupButtonAction) { + self.title = title + self.titleWhenForwarded = titleWhenForwarded + self.action = action + } + + public init(decoder: PostboxDecoder) { + self.title = decoder.decodeStringForKey(".t", orElse: "") + self.titleWhenForwarded = decoder.decodeOptionalStringForKey(".tf") + self.action = ReplyMarkupButtonAction(decoder: decoder) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.title, forKey: ".t") + if let titleWhenForwarded = self.titleWhenForwarded { + encoder.encodeString(titleWhenForwarded, forKey: ".tf") + } else { + encoder.encodeNil(forKey: ".tf") + } + self.action.encode(encoder) + } + + public static func ==(lhs: ReplyMarkupButton, rhs: ReplyMarkupButton) -> Bool { + return lhs.title == rhs.title && lhs.action == rhs.action + } +} + +public struct ReplyMarkupRow: PostboxCoding, Equatable { + public let buttons: [ReplyMarkupButton] + + init(buttons: [ReplyMarkupButton]) { + self.buttons = buttons + } + + public init(decoder: PostboxDecoder) { + self.buttons = decoder.decodeObjectArrayWithDecoderForKey("b") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.buttons, forKey: "b") + } + + public static func ==(lhs: ReplyMarkupRow, rhs: ReplyMarkupRow) -> Bool { + return lhs.buttons == rhs.buttons + } +} + +public struct ReplyMarkupMessageFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let once = ReplyMarkupMessageFlags(rawValue: 1 << 0) + public static let personal = ReplyMarkupMessageFlags(rawValue: 1 << 1) + public static let setupReply = ReplyMarkupMessageFlags(rawValue: 1 << 2) + public static let inline = ReplyMarkupMessageFlags(rawValue: 1 << 3) + public static let fit = ReplyMarkupMessageFlags(rawValue: 1 << 4) +} + +public class ReplyMarkupMessageAttribute: MessageAttribute, Equatable { + public let rows: [ReplyMarkupRow] + public let flags: ReplyMarkupMessageFlags + + init(rows: [ReplyMarkupRow], flags: ReplyMarkupMessageFlags) { + self.rows = rows + self.flags = flags + } + + public required init(decoder: PostboxDecoder) { + self.rows = decoder.decodeObjectArrayWithDecoderForKey("r") + self.flags = ReplyMarkupMessageFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.rows, forKey: "r") + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + } + + public static func ==(lhs: ReplyMarkupMessageAttribute, rhs: ReplyMarkupMessageAttribute) -> Bool { + return lhs.flags == rhs.flags && lhs.rows == rhs.rows + } +} + +extension ReplyMarkupButton { + init(apiButton: Api.KeyboardButton) { + switch apiButton { + case let .keyboardButton(text): + self.init(title: text, titleWhenForwarded: nil, action: .text) + case let .keyboardButtonCallback(text, data): + let memory = malloc(data.size)! + memcpy(memory, data.data, data.size) + let dataBuffer = MemoryBuffer(memory: memory, capacity: data.size, length: data.size, freeWhenDone: true) + self.init(title: text, titleWhenForwarded: nil, action: .callback(dataBuffer)) + case let .keyboardButtonRequestGeoLocation(text): + self.init(title: text, titleWhenForwarded: nil, action: .requestMap) + case let .keyboardButtonRequestPhone(text): + self.init(title: text, titleWhenForwarded: nil, action: .requestPhone) + case let .keyboardButtonSwitchInline(flags, text, query): + self.init(title: text, titleWhenForwarded: nil, action: .switchInline(samePeer: (flags & (1 << 0)) != 0, query: query)) + case let .keyboardButtonUrl(text, url): + self.init(title: text, titleWhenForwarded: nil, action: .url(url)) + case let .keyboardButtonGame(text): + self.init(title: text, titleWhenForwarded: nil, action: .openWebApp) + case let .keyboardButtonBuy(text): + self.init(title: text, titleWhenForwarded: nil, action: .payment) + case let .keyboardButtonUrlAuth(_, text, fwdText, url, buttonId): + self.init(title: text, titleWhenForwarded: fwdText, action: .urlAuth(url: url, buttonId: buttonId)) + case let .inputKeyboardButtonUrlAuth(_, text, fwdText, url, _): + self.init(title: text, titleWhenForwarded: fwdText, action: .urlAuth(url: url, buttonId: 0)) + } + } +} + +extension ReplyMarkupRow { + init(apiRow: Api.KeyboardButtonRow) { + switch apiRow { + case let .keyboardButtonRow(buttons): + self.init(buttons: buttons.map { ReplyMarkupButton(apiButton: $0) }) + } + } +} + +extension ReplyMarkupMessageAttribute { + convenience init(apiMarkup: Api.ReplyMarkup) { + var rows: [ReplyMarkupRow] = [] + var flags = ReplyMarkupMessageFlags() + switch apiMarkup { + case let .replyKeyboardMarkup(markupFlags, apiRows): + rows = apiRows.map { ReplyMarkupRow(apiRow: $0) } + if (markupFlags & (1 << 0)) != 0 { + flags.insert(.fit) + } + if (markupFlags & (1 << 1)) != 0 { + flags.insert(.once) + } + if (markupFlags & (1 << 2)) != 0 { + flags.insert(.personal) + } + case let .replyInlineMarkup(apiRows): + rows = apiRows.map { ReplyMarkupRow(apiRow: $0) } + flags.insert(.inline) + case let .replyKeyboardForceReply(forceReplyFlags): + if (forceReplyFlags & (1 << 1)) != 0 { + flags.insert(.once) + } + if (forceReplyFlags & (1 << 2)) != 0 { + flags.insert(.personal) + } + flags.insert(.setupReply) + case let .replyKeyboardHide(hideFlags): + if (hideFlags & (1 << 2)) != 0 { + flags.insert(.personal) + } + } + self.init(rows: rows, flags: flags) + } +} diff --git a/submodules/TelegramCore/TelegramCore/ReplyMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ReplyMessageAttribute.swift new file mode 100644 index 0000000000..83c12f4c05 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ReplyMessageAttribute.swift @@ -0,0 +1,29 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ReplyMessageAttribute: MessageAttribute { + public let messageId: MessageId + + public var associatedMessageIds: [MessageId] { + return [self.messageId] + } + + public init(messageId: MessageId) { + self.messageId = messageId + } + + required public init(decoder: PostboxDecoder) { + let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i", orElse: 0) + self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) + } + + public func encode(_ encoder: PostboxEncoder) { + let namespaceAndId = Int64(self.messageId.namespace) | (Int64(self.messageId.id) << 32) + encoder.encodeInt64(namespaceAndId, forKey: "i") + encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") + } +} diff --git a/submodules/TelegramCore/TelegramCore/ReportPeer.swift b/submodules/TelegramCore/TelegramCore/ReportPeer.swift new file mode 100644 index 0000000000..2f318b8f0d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ReportPeer.swift @@ -0,0 +1,205 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func reportPeer(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if let peer = peer as? TelegramSecretChat { + return account.network.request(Api.functions.messages.reportEncryptedSpam(peer: Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash))) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if result != nil { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedUserData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedGroupData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedChannelData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return current + } + }) + } + } + } + } else if let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.reportSpam(peer: inputPeer)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if result != nil { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedUserData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedGroupData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedChannelData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return current + } + }) + } + } + } + } else { + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} + +public enum ReportReason: Equatable { + case spam + case violence + case porno + case childAbuse + case copyright + case custom(String) +} + +private extension ReportReason { + var apiReason: Api.ReportReason { + switch self { + case .spam: + return .inputReportReasonSpam + case .violence: + return .inputReportReasonViolence + case .porno: + return .inputReportReasonPornography + case .childAbuse: + return .inputReportReasonChildAbuse + case .copyright: + return .inputReportReasonCopyright + case let .custom(text): + return .inputReportReasonOther(text: text) + } + } +} + +public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} + +public func reportPeerMessages(account: Account, messageIds: [MessageId], reason: ReportReason) -> Signal { + return account.postbox.transaction { transaction -> Signal in + let groupedIds = messagesIdsGroupedByPeerId(messageIds) + let signals = groupedIds.values.compactMap { ids -> Signal? in + guard let peerId = ids.first?.peerId, let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else { + return nil + } + return account.network.request(Api.functions.messages.report(peer: inputPeer, id: ids.map { $0.id }, reason: reason.apiReason)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } + + return combineLatest(signals) + |> mapToSignal { _ -> Signal in + return .complete() + } + } |> switchToLatest +} + +public func reportSupergroupPeer(account: Account, peerId: PeerId, memberId: PeerId, messageIds: [MessageId]) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputChannel(peer), let memberPeer = transaction.getPeer(memberId), let inputMember = apiInputUser(memberPeer) { + return account.network.request(Api.functions.channels.reportSpam(channel: inputPeer, userId: inputMember, id: messageIds.map({$0.id}))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} + +public func dismissPeerStatusOptions(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Signal in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedUserData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedGroupData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedChannelData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else if let current = current as? CachedSecretChatData { + var peerStatusSettings = current.peerStatusSettings ?? PeerStatusSettings() + peerStatusSettings = [] + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return current + } + }) + + if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.hidePeerSettingsBar(peer: inputPeer)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/RequestChatContextResults.swift b/submodules/TelegramCore/TelegramCore/RequestChatContextResults.swift new file mode 100644 index 0000000000..185fb6bfa9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestChatContextResults.swift @@ -0,0 +1,47 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func requestChatContextResults(account: Account, botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String) -> Signal { + return combineLatest(account.postbox.transaction { transaction -> (bot: Peer, peer: Peer)? in + if let bot = transaction.getPeer(botId), let peer = transaction.getPeer(peerId) { + return (bot, peer) + } else { + return nil + } + }, location) + |> mapToSignal { botAndPeer, location -> Signal in + if let (bot, peer) = botAndPeer, let inputBot = apiInputUser(bot) { + var flags: Int32 = 0 + var inputPeer: Api.InputPeer = .inputPeerEmpty + var geoPoint: Api.InputGeoPoint? + if let actualInputPeer = apiInputPeer(peer) { + inputPeer = actualInputPeer + } + if let (latitude, longitude) = location { + flags |= (1 << 0) + geoPoint = Api.InputGeoPoint.inputGeoPoint(lat: latitude, long: longitude) + } + return account.network.request(Api.functions.messages.getInlineBotResults(flags: flags, bot: inputBot, peer: inputPeer, geoPoint: geoPoint, query: query, offset: offset)) + |> map { result -> ChatContextResultCollection? in + return ChatContextResultCollection(apiResults: result, botId: bot.id, peerId: peerId, query: query, geoPoint: location) + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + return .single(nil) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RequestEditMessage.swift b/submodules/TelegramCore/TelegramCore/RequestEditMessage.swift new file mode 100644 index 0000000000..e8e816d3be --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestEditMessage.swift @@ -0,0 +1,251 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum RequestEditMessageMedia : Equatable { + case keep + case update(AnyMediaReference) +} + +public enum RequestEditMessageResult { + case progress(Float) + case done(Bool) +} + +private enum RequestEditMessageInternalError { + case error(RequestEditMessageError) + case invalidReference +} + +public enum RequestEditMessageError { + case generic + case restricted +} + +public func requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false) -> Signal { + return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, forceReupload: false) + |> `catch` { error -> Signal in + if case .invalidReference = error { + return requestEditMessageInternal(account: account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, forceReupload: true) + } else { + return .fail(error) + } + } + |> mapError { error -> RequestEditMessageError in + switch error { + case let .error(error): + return error + default: + return .generic + } + } +} + +private func requestEditMessageInternal(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, forceReupload: Bool) -> Signal { + let uploadedMedia: Signal + switch media { + case .keep: + uploadedMedia = .single(.progress(0.0)) + |> then(.single(nil)) + case let .update(media): + let generateUploadSignal: (Bool) -> Signal? = { forceReupload in + let augmentedMedia = augmentMediaWithReference(media) + return mediaContentToUpload(network: account.network, postbox: account.postbox, auxiliaryMethods: account.auxiliaryMethods, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, revalidationContext: account.mediaReferenceRevalidationContext, forceReupload: forceReupload, isGrouped: false, peerId: messageId.peerId, media: augmentedMedia, text: "", autoremoveAttribute: nil, messageId: nil, attributes: []) + } + if let uploadSignal = generateUploadSignal(forceReupload) { + uploadedMedia = .single(.progress(0.027)) + |> then(uploadSignal) + |> map { result -> PendingMessageUploadedContentResult? in + switch result { + case let .progress(value): + return .progress(max(value, 0.027)) + case let .content(content): + return .content(content) + } + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + uploadedMedia = .single(nil) + } + } + return uploadedMedia + |> mapError { _ -> RequestEditMessageInternalError in return .error(.generic) } + |> mapToSignal { uploadedMediaResult -> Signal in + var pendingMediaContent: PendingMessageUploadedContent? + if let uploadedMediaResult = uploadedMediaResult { + switch uploadedMediaResult { + case let .progress(value): + return .single(.progress(value)) + case let .content(content): + pendingMediaContent = content.content + } + } + return account.postbox.transaction { transaction -> (Peer?, SimpleDictionary) in + guard let message = transaction.getMessage(messageId) else { + return (nil, SimpleDictionary()) + } + + if text.isEmpty { + for media in message.media { + switch media { + case _ as TelegramMediaImage, _ as TelegramMediaFile: + break + default: + return (nil, SimpleDictionary()) + } + } + } + + var peers = SimpleDictionary() + + if let entities = entities { + for peerId in entities.associatedPeerIds { + if let peer = transaction.getPeer(peerId) { + peers[peer.id] = peer + } + } + } + return (transaction.getPeer(messageId.peerId), peers) + } + |> mapError { _ -> RequestEditMessageInternalError in return .error(.generic) } + |> mapToSignal { peer, associatedPeers -> Signal in + if let peer = peer, let inputPeer = apiInputPeer(peer) { + var flags: Int32 = 1 << 11 + + var apiEntities: [Api.MessageEntity]? + if let entities = entities { + apiEntities = apiTextAttributeEntities(entities, associatedPeers: associatedPeers) + flags |= Int32(1 << 3) + } + + if disableUrlPreview { + flags |= Int32(1 << 1) + } + + var inputMedia: Api.InputMedia? = nil + if let pendingMediaContent = pendingMediaContent { + switch pendingMediaContent { + case let .media(media, _): + inputMedia = media + default: + break + } + } + if let _ = inputMedia { + flags |= Int32(1 << 14) + } + + return account.network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities)) + |> map { result -> Api.Updates? in + return result + } + |> `catch` { error -> Signal in + if error.errorDescription == "MESSAGE_NOT_MODIFIED" { + return .single(nil) + } else { + return .fail(error) + } + } + |> mapError { error -> RequestEditMessageInternalError in + if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") { + return .invalidReference + } else if error.errorDescription.hasPrefix("CHAT_SEND_") && error.errorDescription.hasSuffix("_FORBIDDEN") { + return .error(.restricted) + } + return .error(.generic) + } + |> mapToSignal { result -> Signal in + if let result = result { + return account.postbox.transaction { transaction -> RequestEditMessageResult in + var toMedia: Media? + if let message = result.messages.first.flatMap(StoreMessage.init(apiMessage:)) { + toMedia = message.media.first + } + + if case let .update(fromMedia) = media, let toMedia = toMedia { + applyMediaResourceChanges(from: fromMedia.media, to: toMedia, postbox: account.postbox) + } + account.stateManager.addUpdates(result) + + return .done(true) + } + |> mapError { _ -> RequestEditMessageInternalError in + return .error(.generic) + } + } else { + return .single(.done(false)) + } + } + } else { + return .single(.done(false)) + } + } + } +} + +public func requestEditLiveLocation(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId, coordinate: (latitude: Double, longitude: Double)?) -> Signal { + return postbox.transaction { transaction -> (Api.InputPeer, TelegramMediaMap)? in + guard let inputPeer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else { + return nil + } + guard let message = transaction.getMessage(messageId) else { + return nil + } + for media in message.media { + if let media = media as? TelegramMediaMap { + return (inputPeer, media) + } + } + return nil + } + |> mapToSignal { inputPeerAndMedia -> Signal in + guard let (inputPeer, media) = inputPeerAndMedia else { + return .complete() + } + let inputMedia: Api.InputMedia + if let coordinate = coordinate, let liveBroadcastingTimeout = media.liveBroadcastingTimeout { + inputMedia = .inputMediaGeoLive(flags: 1 << 1, geoPoint: .inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude), period: liveBroadcastingTimeout) + } else { + inputMedia = .inputMediaGeoLive(flags: 1 << 0, geoPoint: .inputGeoPoint(lat: media.latitude, long: media.longitude), period: nil) + } + return network.request(Api.functions.messages.editMessage(flags: 1 << 14, peer: inputPeer, id: messageId.id, message: nil, media: inputMedia, replyMarkup: nil, entities: nil)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + if coordinate == nil { + return postbox.transaction { transaction -> Void in + transaction.updateMessage(messageId, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var updatedLocalTags = currentMessage.localTags + updatedLocalTags.remove(.OutgoingLiveLocation) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: updatedLocalTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } + } else { + return .complete() + } + } + } +} + diff --git a/submodules/TelegramCore/TelegramCore/RequestMessageActionCallback.swift b/submodules/TelegramCore/TelegramCore/RequestMessageActionCallback.swift new file mode 100644 index 0000000000..cf67c661b0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestMessageActionCallback.swift @@ -0,0 +1,132 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum MessageActionCallbackResult { + case none + case alert(String) + case toast(String) + case url(String) +} + +public func requestMessageActionCallback(account: Account, messageId: MessageId, isGame:Bool, data: MemoryBuffer?) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + var flags: Int32 = 0 + var dataBuffer: Buffer? + if let data = data { + flags |= Int32(1 << 0) + dataBuffer = Buffer(data: data.makeData()) + } + if isGame { + flags |= Int32(1 << 1) + } + return account.network.request(Api.functions.messages.getBotCallbackAnswer(flags: flags, peer: inputPeer, msgId: messageId.id, data: dataBuffer)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> MessageActionCallbackResult in + guard let result = result else { + return .none + } + switch result { + case let .botCallbackAnswer(flags, message, url, cacheTime): + if let message = message { + if (flags & (1 << 1)) != 0 { + return .alert(message) + } else { + return .toast(message) + } + } else if let url = url { + return .url(url) + } else { + return .none + } + } + } + } else { + return .single(.none) + } + } +} + +public enum MessageActionUrlAuthResult { + case `default` + case accepted(String) + case request(String, Peer, Bool) +} + + +public func requestMessageActionUrlAuth(account: Account, messageId: MessageId, buttonId: Int32) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.requestUrlAuth(peer: inputPeer, msgId: messageId.id, buttonId: buttonId)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> MessageActionUrlAuthResult in + guard let result = result else { + return .default + } + switch result { + case .urlAuthResultDefault: + return .default + case let .urlAuthResultAccepted(url): + return .accepted(url) + case let .urlAuthResultRequest(flags, bot, domain): + return .request(domain, TelegramUser(user: bot), (flags & (1 << 0)) != 0) + } + } + } else { + return .single(.default) + } + } +} + +public func acceptMessageActionUrlAuth(account: Account, messageId: MessageId, buttonId: Int32, allowWriteAccess: Bool) -> Signal { + return account.postbox.loadedPeerWithId(messageId.peerId) + |> take(1) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + var flags: Int32 = 0 + if allowWriteAccess { + flags |= Int32(1 << 0) + } + return account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: inputPeer, msgId: messageId.id, buttonId: buttonId)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> MessageActionUrlAuthResult in + guard let result = result else { + return .default + } + switch result { + case let .urlAuthResultAccepted(url): + return .accepted(url) + default: + return .default + } + } + } else { + return .single(.default) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RequestPhoneNumber.swift b/submodules/TelegramCore/TelegramCore/RequestPhoneNumber.swift new file mode 100644 index 0000000000..91c2958519 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestPhoneNumber.swift @@ -0,0 +1,32 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public func requestPhoneNumber(account: Account, peerId: PeerId) -> Signal { + return .never() + /*return account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer = inputPeer else { + return .complete() + } + return account.network.request(Api.functions.messages.sendPhoneNumberRequest(peer: inputPeer, randomId: arc4random64())) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + } + return .complete() + } + }*/ +} + diff --git a/submodules/TelegramCore/TelegramCore/RequestSecureIdForm.swift b/submodules/TelegramCore/TelegramCore/RequestSecureIdForm.swift new file mode 100644 index 0000000000..77945ac9d1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestSecureIdForm.swift @@ -0,0 +1,306 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public enum RequestSecureIdFormError { + case generic + case serverError(String) + case versionOutdated +} + +private func parseSecureValueType(_ type: Api.SecureValueType, selfie: Bool, translation: Bool, nativeNames: Bool) -> SecureIdRequestedFormFieldValue { + switch type { + case .secureValueTypePersonalDetails: + return .personalDetails(nativeName: nativeNames) + case .secureValueTypePassport: + return .passport(selfie: selfie, translation: translation) + case .secureValueTypeInternalPassport: + return .internalPassport(selfie: selfie, translation: translation) + case .secureValueTypeDriverLicense: + return .driversLicense(selfie: selfie, translation: translation) + case .secureValueTypeIdentityCard: + return .idCard(selfie: selfie, translation: translation) + case .secureValueTypeAddress: + return .address + case .secureValueTypeUtilityBill: + return .utilityBill(translation: translation) + case .secureValueTypeBankStatement: + return .bankStatement(translation: translation) + case .secureValueTypeRentalAgreement: + return .rentalAgreement(translation: translation) + case .secureValueTypePhone: + return .phone + case .secureValueTypeEmail: + return .email + case .secureValueTypePassportRegistration: + return .passportRegistration(translation: translation) + case .secureValueTypeTemporaryRegistration: + return .temporaryRegistration(translation: translation) + } +} + +private func parseSecureData(_ value: Api.SecureData) -> (data: Data, hash: Data, secret: Data) { + switch value { + case let .secureData(data, dataHash, secret): + return (data.makeData(), dataHash.makeData(), secret.makeData()) + } +} + +struct ParsedSecureValue { + let valueWithContext: SecureIdValueWithContext +} + +func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, errors: [Api.SecureValueError]) -> ParsedSecureValue? { + switch value { + case let .secureValue(_, type, data, frontSide, reverseSide, selfie, translation, files, plainData, hash): + let parsedFileReferences = files.flatMap { $0.compactMap(SecureIdFileReference.init) } ?? [] + let parsedFiles = parsedFileReferences.map(SecureIdVerificationDocumentReference.remote) + let parsedTranslationReferences = translation.flatMap { $0.compactMap(SecureIdFileReference.init) } ?? [] + let parsedTranslations = parsedTranslationReferences.map(SecureIdVerificationDocumentReference.remote) + let parsedFrontSide = frontSide.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) + let parsedBackSide = reverseSide.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) + let parsedSelfie = selfie.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) + + let decryptedData: Data? + let encryptedMetadata: SecureIdEncryptedValueMetadata? + var parsedFileMetadata: [SecureIdEncryptedValueFileMetadata] = [] + var parsedTranslationMetadata: [SecureIdEncryptedValueFileMetadata] = [] + var parsedSelfieMetadata: SecureIdEncryptedValueFileMetadata? + var parsedFrontSideMetadata: SecureIdEncryptedValueFileMetadata? + var parsedBackSideMetadata: SecureIdEncryptedValueFileMetadata? + var contentsId: Data? + if let data = data { + let (encryptedData, decryptedHash, encryptedSecret) = parseSecureData(data) + guard let valueContext = decryptedSecureValueAccessContext(context: context, encryptedSecret: encryptedSecret, decryptedDataHash: decryptedHash) else { + return nil + } + + contentsId = decryptedHash + + decryptedData = decryptedSecureValueData(context: valueContext, encryptedData: encryptedData, decryptedDataHash: decryptedHash) + if decryptedData == nil { + return nil + } + encryptedMetadata = SecureIdEncryptedValueMetadata(valueDataHash: decryptedHash, decryptedSecret: valueContext.secret) + } else { + decryptedData = nil + encryptedMetadata = nil + } + for file in parsedFileReferences { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: file.fileHash, encryptedSecret: file.encryptedSecret) else { + return nil + } + parsedFileMetadata.append(SecureIdEncryptedValueFileMetadata(hash: file.fileHash, secret: fileSecret)) + } + for file in parsedTranslationReferences { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: file.fileHash, encryptedSecret: file.encryptedSecret) else { + return nil + } + parsedTranslationMetadata.append(SecureIdEncryptedValueFileMetadata(hash: file.fileHash, secret: fileSecret)) + } + if let parsedSelfie = selfie.flatMap(SecureIdFileReference.init) { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: parsedSelfie.fileHash, encryptedSecret: parsedSelfie.encryptedSecret) else { + return nil + } + + parsedSelfieMetadata = SecureIdEncryptedValueFileMetadata(hash: parsedSelfie.fileHash, secret: fileSecret) + } + if let parsedFrontSide = frontSide.flatMap(SecureIdFileReference.init) { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: parsedFrontSide.fileHash, encryptedSecret: parsedFrontSide.encryptedSecret) else { + return nil + } + + parsedFrontSideMetadata = SecureIdEncryptedValueFileMetadata(hash: parsedFrontSide.fileHash, secret: fileSecret) + } + if let parsedBackSide = reverseSide.flatMap(SecureIdFileReference.init) { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: parsedBackSide.fileHash, encryptedSecret: parsedBackSide.encryptedSecret) else { + return nil + } + + parsedBackSideMetadata = SecureIdEncryptedValueFileMetadata(hash: parsedBackSide.fileHash, secret: fileSecret) + } + + let value: SecureIdValue + + switch type { + case .secureValueTypePersonalDetails: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let personalDetails = SecureIdPersonalDetailsValue(dict: dict, fileReferences: parsedFiles) else { + return nil + } + value = .personalDetails(personalDetails) + case .secureValueTypePassport: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let passport = SecureIdPassportValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { + return nil + } + value = .passport(passport) + case .secureValueTypeInternalPassport: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let internalPassport = SecureIdInternalPassportValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { + return nil + } + value = .internalPassport(internalPassport) + case .secureValueTypeDriverLicense: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let driversLicense = SecureIdDriversLicenseValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { + return nil + } + value = .driversLicense(driversLicense) + case .secureValueTypeIdentityCard: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let idCard = SecureIdIDCardValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { + return nil + } + value = .idCard(idCard) + case .secureValueTypeAddress: + guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { + return nil + } + guard let address = SecureIdAddressValue(dict: dict, fileReferences: parsedFiles) else { + return nil + } + value = .address(address) + case .secureValueTypePassportRegistration: + guard let passportRegistration = SecureIdPassportRegistrationValue(fileReferences: parsedFiles, translations: parsedTranslations) else { + return nil + } + value = .passportRegistration(passportRegistration) + case .secureValueTypeTemporaryRegistration: + guard let temporaryRegistration = SecureIdTemporaryRegistrationValue(fileReferences: parsedFiles, translations: parsedTranslations) else { + return nil + } + value = .temporaryRegistration(temporaryRegistration) + case .secureValueTypeUtilityBill: + guard let utilityBill = SecureIdUtilityBillValue(fileReferences: parsedFiles, translations: parsedTranslations) else { + return nil + } + value = .utilityBill(utilityBill) + case .secureValueTypeBankStatement: + guard let bankStatement = SecureIdBankStatementValue(fileReferences: parsedFiles, translations: parsedTranslations) else { + return nil + } + value = .bankStatement(bankStatement) + case .secureValueTypeRentalAgreement: + guard let rentalAgreement = SecureIdRentalAgreementValue(fileReferences: parsedFiles, translations: parsedTranslations) else { + return nil + } + value = .rentalAgreement(rentalAgreement) + case .secureValueTypePhone: + guard let publicData = plainData else { + return nil + } + switch publicData { + case let .securePlainPhone(phone): + value = .phone(SecureIdPhoneValue(phone: phone)) + default: + return nil + } + case .secureValueTypeEmail: + guard let publicData = plainData else { + return nil + } + switch publicData { + case let .securePlainEmail(email): + value = .email(SecureIdEmailValue(email: email)) + default: + return nil + } + } + + return ParsedSecureValue(valueWithContext: SecureIdValueWithContext(value: value, errors: parseSecureIdValueContentErrors(dataHash: contentsId, fileHashes: Set(parsedFileMetadata.map { $0.hash } + parsedTranslationMetadata.map { $0.hash}), selfieHash: parsedSelfieMetadata?.hash, frontSideHash: parsedFrontSideMetadata?.hash, backSideHash: parsedBackSideMetadata?.hash, errors: errors), files: parsedFileMetadata, translations: parsedTranslationMetadata, selfie: parsedSelfieMetadata, frontSide: parsedFrontSideMetadata, backSide: parsedBackSideMetadata, encryptedMetadata: encryptedMetadata, opaqueHash: hash.makeData())) + } +} + +private func parseSecureValues(context: SecureIdAccessContext, values: [Api.SecureValue], errors: [Api.SecureValueError], requestedFields: [SecureIdRequestedFormField]) -> [SecureIdValueWithContext] { + return values.map({ apiValue in + return parseSecureValue(context: context, value: apiValue, errors: errors) + }).compactMap({ $0?.valueWithContext }) +} + +public struct EncryptedSecureIdForm { + public let peerId: PeerId + public let requestedFields: [SecureIdRequestedFormField] + public let termsUrl: String? + + let encryptedValues: [Api.SecureValue] + let errors: [Api.SecureValueError] +} + +public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: PeerId, scope: String, publicKey: String) -> Signal { + if peerId.namespace != Namespaces.Peer.CloudUser { + return .fail(.serverError("BOT_INVALID")) + } + if scope.isEmpty { + return .fail(.serverError("SCOPE_EMPTY")) + } + if publicKey.isEmpty { + return .fail(.serverError("PUBLIC_KEY_REQUIRED")) + } + return network.request(Api.functions.account.getAuthorizationForm(botId: peerId.id, scope: scope, publicKey: publicKey)) + |> mapError { error -> RequestSecureIdFormError in + switch error.errorDescription { + case "APP_VERSION_OUTDATED": + return .versionOutdated + default: + return .serverError(error.errorDescription) + } + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> EncryptedSecureIdForm in + switch result { + case let .authorizationForm(_, requiredTypes, values, errors, users, termsUrl): + var peers: [Peer] = [] + for user in users { + let parsed = TelegramUser(user: user) + peers.append(parsed) + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated in + return updated + }) + + return EncryptedSecureIdForm(peerId: peerId, requestedFields: requiredTypes.map { requiredType in + switch requiredType { + case let .secureRequiredType(flags, type): + return .just(parseSecureValueType(type, selfie: (flags & 1 << 1) != 0, translation: (flags & 1 << 2) != 0, nativeNames: (flags & 1 << 0) != 0)) + case let .secureRequiredTypeOneOf(types): + let parsedInnerTypes = types.compactMap { innerType -> SecureIdRequestedFormFieldValue? in + switch innerType { + case let .secureRequiredType(flags, type): + return parseSecureValueType(type, selfie: (flags & 1 << 1) != 0, translation: (flags & 1 << 2) != 0, nativeNames: (flags & 1 << 0) != 0) + case .secureRequiredTypeOneOf: + return nil + } + } + return .oneOf(parsedInnerTypes) + } + }, termsUrl: termsUrl, encryptedValues: values, errors: errors) + } + } |> mapError { _ in return RequestSecureIdFormError.generic } + } +} + +public func decryptedSecureIdForm(context: SecureIdAccessContext, form: EncryptedSecureIdForm) -> SecureIdForm? { + return SecureIdForm(peerId: form.peerId, requestedFields: form.requestedFields, values: parseSecureValues(context: context, values: form.encryptedValues, errors: form.errors, requestedFields: form.requestedFields)) +} diff --git a/submodules/TelegramCore/TelegramCore/RequestStartBot.swift b/submodules/TelegramCore/TelegramCore/RequestStartBot.swift new file mode 100644 index 0000000000..03d47282df --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestStartBot.swift @@ -0,0 +1,97 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func requestStartBot(account: Account, botPeerId: PeerId, payload: String?) -> Signal { + if let payload = payload, !payload.isEmpty { + return account.postbox.loadedPeerWithId(botPeerId) + |> mapToSignal { botPeer -> Signal in + if let inputUser = apiInputUser(botPeer) { + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + let r = account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: randomId, startParam: payload)) + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + return r + |> retryRequest + } else { + return .complete() + } + } + } else { + return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]) |> mapToSignal { _ -> Signal in + return .complete() + } + } +} + +public enum RequestStartBotInGroupError { + case generic +} + +public enum StartBotInGroupResult { + case none + case channelParticipant(RenderedChannelParticipant) +} + +public func requestStartBotInGroup(account: Account, botPeerId: PeerId, groupPeerId: PeerId, payload: String?) -> Signal { + return account.postbox.transaction { transaction -> (Peer?, Peer?) in + return (transaction.getPeer(botPeerId), transaction.getPeer(groupPeerId)) + } + |> mapError { _ -> RequestStartBotInGroupError in return .generic } + |> mapToSignal { botPeer, groupPeer -> Signal in + if let botPeer = botPeer, let inputUser = apiInputUser(botPeer), let groupPeer = groupPeer, let inputGroup = apiInputPeer(groupPeer) { + var randomId: Int64 = 0 + arc4random_buf(&randomId, 8) + let request = account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: inputGroup, randomId: randomId, startParam: payload ?? "")) + |> mapError { _ -> RequestStartBotInGroupError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + if groupPeerId.namespace == Namespaces.Peer.CloudChannel { + return fetchChannelParticipant(account: account, peerId: groupPeerId, participantId: botPeerId) + |> mapError { _ -> RequestStartBotInGroupError in return .generic + } + |> mapToSignal { participant -> Signal in + return account.postbox.transaction { transaction -> StartBotInGroupResult in + if let participant = participant, let peer = transaction.getPeer(participant.peerId) { + var peers: [PeerId: Peer] = [:] + let presences: [PeerId: PeerPresence] = [:] + + peers[peer.id] = peer + return .channelParticipant(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences)) + } else { + return .none + } + } + |> mapError { _ -> RequestStartBotInGroupError in return .generic + } + } + } else { + return .single(.none) + } + } + + return request + } else { + return .complete() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RequestUserPhotos.swift b/submodules/TelegramCore/TelegramCore/RequestUserPhotos.swift new file mode 100644 index 0000000000..e4255b051d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RequestUserPhotos.swift @@ -0,0 +1,150 @@ + +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + + +public struct TelegramPeerPhoto { + public let image: TelegramMediaImage + public let date: Int32 + public let reference: TelegramMediaImageReference? + public let index:Int + public let totalCount:Int +} + +public func requestPeerPhotos(account:Account, peerId: PeerId) -> Signal<[TelegramPeerPhoto], NoError> { + return account.postbox.transaction{ transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> mapToSignal { peer -> Signal<[TelegramPeerPhoto], NoError> in + if let peer = peer as? TelegramUser, let inputUser = apiInputUser(peer) { + return account.network.request(Api.functions.photos.getUserPhotos(userId: inputUser, offset: 0, maxId: 0, limit: 100)) + |> map {Optional($0)} + |> mapError {_ in} + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> [TelegramPeerPhoto] in + if let result = result { + let totalCount:Int + let photos:[Api.Photo] + switch result { + case let .photos(data): + photos = data.photos + totalCount = photos.count + case let .photosSlice(data): + photos = data.photos + totalCount = Int(data.count) + } + + var images: [TelegramPeerPhoto] = [] + for i in 0 ..< photos.count { + if let image = telegramMediaImageFromApiPhoto(photos[i]), let reference = image.reference { + var date: Int32 = 0 + switch photos[i] { + case let .photo(_, _, _, _, apiDate, _, _): + date = apiDate + case .photoEmpty: + break + } + images.append(TelegramPeerPhoto(image: image, date: date, reference: reference, index: i, totalCount: totalCount)) + } + } + + return images + } else { + return [] + } + } + } else if let peer = peer, let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal<[TelegramPeerPhoto], NoError> in + if let result = result { + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + + return account.postbox.transaction { transaction -> [Message] in + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + var renderedMessages: [Message] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + renderedMessages.append(renderedMessage) + } + } + + return renderedMessages + } |> map { messages -> [TelegramPeerPhoto] in + var photos: [TelegramPeerPhoto] = [] + var index:Int = 0 + for message in messages { + if let media = message.media.first as? TelegramMediaAction { + switch media.action { + case let .photoUpdated(image): + if let image = image { + photos.append(TelegramPeerPhoto(image: image, date: message.timestamp, reference: nil, index: index, totalCount: messages.count)) + } + default: + break + } + } + index += 1 + } + return photos + } + + } else { + return .single([]) + } + } + } else { + return .single([]) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ResolvePeerByName.swift b/submodules/TelegramCore/TelegramCore/ResolvePeerByName.swift new file mode 100644 index 0000000000..b990fe8b62 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ResolvePeerByName.swift @@ -0,0 +1,121 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +final class CachedResolvedByNamePeer: PostboxCoding { + let peerId: PeerId? + let timestamp: Int32 + + static func key(name: String) -> ValueBoxKey { + let key: ValueBoxKey + if let nameData = name.data(using: .utf8) { + key = ValueBoxKey(length: nameData.count) + nameData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(key.memory, bytes, nameData.count) + } + } else { + key = ValueBoxKey(length: 0) + } + return key + } + + init(peerId: PeerId?, timestamp: Int32) { + self.peerId = peerId + self.timestamp = timestamp + } + + init(decoder: PostboxDecoder) { + if let peerId = decoder.decodeOptionalInt64ForKey("p") { + self.peerId = PeerId(peerId) + } else { + self.peerId = nil + } + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + if let peerId = self.peerId { + encoder.encodeInt64(peerId.toInt64(), forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + encoder.encodeInt32(self.timestamp, forKey: "t") + } +} + +private let resolvedByNamePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200) + +public enum ResolvePeerByNameOptionCached { + case none + case cached + case cachedIfLaterThan(timestamp: Int32) +} + +public enum ResolvePeerByNameOptionRemote { + case updateIfEarlierThan(timestamp: Int32) + case update +} + +public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal { + var normalizedName = name + if normalizedName.hasPrefix("@") { + normalizedName = String(normalizedName[name.index(after: name.startIndex)...]) + } + + return account.postbox.transaction { transaction -> CachedResolvedByNamePeer? in + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName))) as? CachedResolvedByNamePeer + } |> mapToSignal { cachedEntry -> Signal in + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + if let cachedEntry = cachedEntry, cachedEntry.timestamp <= timestamp && cachedEntry.timestamp >= timestamp - ageLimit { + return .single(cachedEntry.peerId) + } else { + return account.network.request(Api.functions.contacts.resolveUsername(username: normalizedName)) + |> mapError { _ -> Void in + return Void() + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> PeerId? in + var peerId: PeerId? = nil + + switch result { + case let .resolvedPeer(apiPeer, chats, users): + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + if let peer = peers[apiPeer.peerId] { + peerId = peer.id + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated -> Peer in + return updated + }) + } + } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp), collectionSpec: resolvedByNamePeersCollectionSpec) + return peerId + } + |> introduceError(Void.self) + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/RichText.swift b/submodules/TelegramCore/TelegramCore/RichText.swift new file mode 100644 index 0000000000..45f1366038 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/RichText.swift @@ -0,0 +1,339 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +private enum RichTextTypes: Int32 { + case empty = 0 + case plain = 1 + case bold = 2 + case italic = 3 + case underline = 4 + case strikethrough = 5 + case fixed = 6 + case url = 7 + case email = 8 + case concat = 9 + case `subscript` = 10 + case superscript = 11 + case marked = 12 + case phone = 13 + case image = 14 + case anchor = 15 +} + +public indirect enum RichText: PostboxCoding, Equatable { + case empty + case plain(String) + case bold(RichText) + case italic(RichText) + case underline(RichText) + case strikethrough(RichText) + case fixed(RichText) + case url(text: RichText, url: String, webpageId: MediaId?) + case email(text: RichText, email: String) + case concat([RichText]) + case `subscript`(RichText) + case superscript(RichText) + case marked(RichText) + case phone(text: RichText, phone: String) + case image(id: MediaId, dimensions: CGSize) + case anchor(text: RichText, name: String) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case RichTextTypes.empty.rawValue: + self = .empty + case RichTextTypes.plain.rawValue: + self = .plain(decoder.decodeStringForKey("s", orElse: "")) + case RichTextTypes.bold.rawValue: + self = .bold(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.italic.rawValue: + self = .italic(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.underline.rawValue: + self = .underline(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.strikethrough.rawValue: + self = .strikethrough(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.fixed.rawValue: + self = .fixed(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.url.rawValue: + let webpageIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("w.n") + let webpageIdId: Int64? = decoder.decodeOptionalInt64ForKey("w.i") + var webpageId: MediaId? + if let webpageIdNamespace = webpageIdNamespace, let webpageIdId = webpageIdId { + webpageId = MediaId(namespace: webpageIdNamespace, id: webpageIdId) + } + self = .url(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, url: decoder.decodeStringForKey("u", orElse: ""), webpageId: webpageId) + case RichTextTypes.email.rawValue: + self = .email(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, email: decoder.decodeStringForKey("e", orElse: "")) + case RichTextTypes.concat.rawValue: + self = .concat(decoder.decodeObjectArrayWithDecoderForKey("a")) + case RichTextTypes.subscript.rawValue: + self = .subscript(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.superscript.rawValue: + self = .superscript(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.marked.rawValue: + self = .marked(decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText) + case RichTextTypes.phone.rawValue: + self = .phone(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, phone: decoder.decodeStringForKey("p", orElse: "")) + case RichTextTypes.image.rawValue: + self = .image(id: MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)), dimensions: CGSize(width: CGFloat(decoder.decodeInt32ForKey("sw", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("sh", orElse: 0)))) + case RichTextTypes.anchor.rawValue: + self = .anchor(text: decoder.decodeObjectForKey("t", decoder: { RichText(decoder: $0) }) as! RichText, name: decoder.decodeStringForKey("n", orElse: "")) + default: + self = .empty + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .empty: + encoder.encodeInt32(RichTextTypes.empty.rawValue, forKey: "r") + case let .plain(string): + encoder.encodeInt32(RichTextTypes.plain.rawValue, forKey: "r") + encoder.encodeString(string, forKey: "s") + case let .bold(text): + encoder.encodeInt32(RichTextTypes.bold.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .italic(text): + encoder.encodeInt32(RichTextTypes.italic.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .underline(text): + encoder.encodeInt32(RichTextTypes.underline.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .strikethrough(text): + encoder.encodeInt32(RichTextTypes.strikethrough.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .fixed(text): + encoder.encodeInt32(RichTextTypes.fixed.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .url(text, url, webpageId): + encoder.encodeInt32(RichTextTypes.url.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeString(url, forKey: "u") + if let webpageId = webpageId { + encoder.encodeInt32(webpageId.namespace, forKey: "w.n") + encoder.encodeInt64(webpageId.id, forKey: "w.i") + } else { + encoder.encodeNil(forKey: "w.n") + encoder.encodeNil(forKey: "w.i") + } + case let .email(text, email): + encoder.encodeInt32(RichTextTypes.email.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeString(email, forKey: "e") + case let .concat(texts): + encoder.encodeInt32(RichTextTypes.concat.rawValue, forKey: "r") + encoder.encodeObjectArray(texts, forKey: "a") + case let .subscript(text): + encoder.encodeInt32(RichTextTypes.subscript.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .superscript(text): + encoder.encodeInt32(RichTextTypes.superscript.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .marked(text): + encoder.encodeInt32(RichTextTypes.marked.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + case let .phone(text, phone): + encoder.encodeInt32(RichTextTypes.phone.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeString(phone, forKey: "p") + case let .image(id, dimensions): + encoder.encodeInt32(RichTextTypes.image.rawValue, forKey: "r") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt64(id.id, forKey: "i.i") + encoder.encodeInt32(Int32(dimensions.width), forKey: "sw") + encoder.encodeInt32(Int32(dimensions.height), forKey: "sh") + case let .anchor(text, name): + encoder.encodeInt32(RichTextTypes.anchor.rawValue, forKey: "r") + encoder.encodeObject(text, forKey: "t") + encoder.encodeString(name, forKey: "n") + } + } + + public static func ==(lhs: RichText, rhs: RichText) -> Bool { + switch lhs { + case .empty: + if case .empty = rhs { + return true + } else { + return false + } + case let .plain(string): + if case .plain(string) = rhs { + return true + } else { + return false + } + case let .bold(text): + if case .bold(text) = rhs { + return true + } else { + return false + } + case let .italic(text): + if case .italic(text) = rhs { + return true + } else { + return false + } + case let .underline(text): + if case .underline(text) = rhs { + return true + } else { + return false + } + case let .strikethrough(text): + if case .strikethrough(text) = rhs { + return true + } else { + return false + } + case let .fixed(text): + if case .fixed(text) = rhs { + return true + } else { + return false + } + case let .url(lhsText, lhsUrl, lhsWebpageId): + if case let .url(rhsText, rhsUrl, rhsWebpageId) = rhs, lhsText == rhsText && lhsUrl == rhsUrl && lhsWebpageId == rhsWebpageId { + return true + } else { + return false + } + case let .email(text, email): + if case .email(text, email) = rhs { + return true + } else { + return false + } + case let .concat(lhsTexts): + if case let .concat(rhsTexts) = rhs, lhsTexts == rhsTexts { + return true + } else { + return false + } + case let .subscript(text): + if case .subscript(text) = rhs { + return true + } else { + return false + } + case let .superscript(text): + if case .superscript(text) = rhs { + return true + } else { + return false + } + case let .marked(text): + if case .marked(text) = rhs { + return true + } else { + return false + } + case let .phone(text, phone): + if case .phone(text, phone) = rhs { + return true + } else { + return false + } + case let .image(id, dimensions): + if case .image(id, dimensions) = rhs { + return true + } else { + return false + } + case let .anchor(text, name): + if case .anchor(text, name) = rhs { + return true + } else { + return false + } + } + } +} + +public extension RichText { + public var plainText: String { + switch self { + case .empty: + return "" + case let .plain(string): + return string + case let .bold(text): + return text.plainText + case let .italic(text): + return text.plainText + case let .underline(text): + return text.plainText + case let .strikethrough(text): + return text.plainText + case let .fixed(text): + return text.plainText + case let .url(text, _, _): + return text.plainText + case let .email(text, _): + return text.plainText + case let .concat(texts): + var string = "" + for text in texts { + string += text.plainText + } + return string + case let .subscript(text): + return text.plainText + case let .superscript(text): + return text.plainText + case let .marked(text): + return text.plainText + case let .phone(text, _): + return text.plainText + case .image: + return "" + case let .anchor(text, _): + return text.plainText + } + } +} + +extension RichText { + init(apiText: Api.RichText) { + switch apiText { + case .textEmpty: + self = .empty + case let .textPlain(text): + self = .plain(text) + case let .textBold(text): + self = .bold(RichText(apiText: text)) + case let .textItalic(text): + self = .italic(RichText(apiText: text)) + case let .textUnderline(text): + self = .underline(RichText(apiText: text)) + case let .textStrike(text): + self = .strikethrough(RichText(apiText: text)) + case let .textFixed(text): + self = .fixed(RichText(apiText: text)) + case let .textUrl(text, url, webpageId): + self = .url(text: RichText(apiText: text), url: url, webpageId: webpageId == 0 ? nil : MediaId(namespace: Namespaces.Media.CloudWebpage, id: webpageId)) + case let .textEmail(text, email): + self = .email(text: RichText(apiText: text), email: email) + case let .textConcat(texts): + self = .concat(texts.map({ RichText(apiText: $0) })) + case let .textSubscript(text): + self = .subscript(RichText(apiText: text)) + case let .textSuperscript(text): + self = .superscript(RichText(apiText: text)) + case let .textMarked(text): + self = .marked(RichText(apiText: text)) + case let .textPhone(text, phone): + self = .phone(text: RichText(apiText: text), phone: phone) + case let .textImage(documentId, w, h): + self = .image(id: MediaId(namespace: Namespaces.Media.CloudFile, id: documentId), dimensions: CGSize(width: CGFloat(w), height: CGFloat(h))) + case let .textAnchor(text, name): + self = .anchor(text: RichText(apiText: text), name: name) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SaveSecureIdValue.swift b/submodules/TelegramCore/TelegramCore/SaveSecureIdValue.swift new file mode 100644 index 0000000000..8cb091f1c6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SaveSecureIdValue.swift @@ -0,0 +1,356 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public enum SaveSecureIdValueError { + case generic + case verificationRequired + case versionOutdated +} + +struct EncryptedSecureData { + let data: Data + let dataHash: Data + let encryptedSecret: Data +} + +func encryptedSecureValueData(context: SecureIdAccessContext, valueContext: SecureIdValueAccessContext, data: Data) -> EncryptedSecureData? { + let valueData = paddedSecureIdData(data) + let valueHash = sha256Digest(valueData) + + let valueSecretHash = sha512Digest(valueContext.secret + valueHash) + let valueKey = valueSecretHash.subdata(in: 0 ..< 32) + let valueIv = valueSecretHash.subdata(in: 32 ..< (32 + 16)) + + guard let encryptedValueData = encryptSecureData(key: valueKey, iv: valueIv, data: valueData, decrypt: false) else { + return nil + } + + let secretHash = sha512Digest(context.secret + valueHash) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + + guard let encryptedValueSecret = encryptSecureData(key: secretKey, iv: secretIv, data: valueContext.secret, decrypt: false) else { + return nil + } + + return EncryptedSecureData(data: encryptedValueData, dataHash: valueHash, encryptedSecret: encryptedValueSecret) +} + +func decryptedSecureValueAccessContext(context: SecureIdAccessContext, encryptedSecret: Data, decryptedDataHash: Data) -> SecureIdValueAccessContext? { + let secretHash = sha512Digest(context.secret + decryptedDataHash) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + + guard let valueSecret = encryptSecureData(key: secretKey, iv: secretIv, data: encryptedSecret, decrypt: true) else { + return nil + } + + if !verifySecureSecret(valueSecret) { + return nil + } + + let valueSecretHash = sha512Digest(valueSecret) + var valueSecretIdValue: Int64 = 0 + valueSecretHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&valueSecretIdValue, bytes.advanced(by: valueSecretHash.count - 8), 8) + } + + return SecureIdValueAccessContext(secret: valueSecret, id: valueSecretIdValue) +} + +func decryptedSecureValueData(context: SecureIdValueAccessContext, encryptedData: Data, decryptedDataHash: Data) -> Data? { + let valueSecretHash = sha512Digest(context.secret + decryptedDataHash) + + let valueKey = valueSecretHash.subdata(in: 0 ..< 32) + let valueIv = valueSecretHash.subdata(in: 32 ..< (32 + 16)) + + guard let decryptedValueData = encryptSecureData(key: valueKey, iv: valueIv, data: encryptedData, decrypt: true) else { + return nil + } + + let checkDataHash = sha256Digest(decryptedValueData) + if checkDataHash != decryptedDataHash { + return nil + } + + guard let unpaddedValueData = unpaddedSecureIdData(decryptedValueData) else { + return nil + } + + return unpaddedValueData +} + +private func apiInputSecretFile(_ file: SecureIdVerificationDocumentReference) -> Api.InputSecureFile { + switch file { + case let .remote(file): + return Api.InputSecureFile.inputSecureFile(id: file.id, accessHash: file.accessHash) + case let .uploaded(file): + return Api.InputSecureFile.inputSecureFileUploaded(id: file.id, parts: file.parts, md5Checksum: file.md5Checksum, fileHash: Buffer(data: file.fileHash), secret: Buffer(data: file.encryptedSecret)) + } +} + +private struct InputSecureIdValueData { + let type: Api.SecureValueType + let dict: [String: Any]? + let fileReferences: [SecureIdVerificationDocumentReference] + let translationReferences: [SecureIdVerificationDocumentReference] + let frontSideReference: SecureIdVerificationDocumentReference? + let backSideReference: SecureIdVerificationDocumentReference? + let selfieReference: SecureIdVerificationDocumentReference? + let publicData: Api.SecurePlainData? +} + +private func inputSecureIdValueData(value: SecureIdValue) -> InputSecureIdValueData { + switch value { + case let .personalDetails(personalDetails): + let (dict, fileReferences) = personalDetails.serialize() + return InputSecureIdValueData(type: .secureValueTypePersonalDetails, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .passport(passport): + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference) = passport.serialize() + return InputSecureIdValueData(type: .secureValueTypePassport, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) + case let .internalPassport(internalPassport): + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference) = internalPassport.serialize() + return InputSecureIdValueData(type: .secureValueTypeInternalPassport, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) + case let .driversLicense(driversLicense): + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference, backSideReference) = driversLicense.serialize() + return InputSecureIdValueData(type: .secureValueTypeDriverLicense, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) + case let .idCard(idCard): + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference, backSideReference) = idCard.serialize() + return InputSecureIdValueData(type: .secureValueTypeIdentityCard, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) + case let .address(address): + let (dict, fileReferences) = address.serialize() + return InputSecureIdValueData(type: .secureValueTypeAddress, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .passportRegistration(passportRegistration): + let (dict, fileReferences, translations) = passportRegistration.serialize() + return InputSecureIdValueData(type: .secureValueTypePassportRegistration, dict: dict, fileReferences: fileReferences, translationReferences: translations, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .temporaryRegistration(temporaryRegistration): + let (dict, fileReferences, translations) = temporaryRegistration.serialize() + return InputSecureIdValueData(type: .secureValueTypeTemporaryRegistration, dict: dict, fileReferences: fileReferences, translationReferences: translations, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .utilityBill(utilityBill): + let (dict, fileReferences, translations) = utilityBill.serialize() + return InputSecureIdValueData(type: .secureValueTypeUtilityBill, dict: dict, fileReferences: fileReferences, translationReferences: translations, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .bankStatement(bankStatement): + let (dict, fileReferences, translations) = bankStatement.serialize() + return InputSecureIdValueData(type: .secureValueTypeBankStatement, dict: dict, fileReferences: fileReferences, translationReferences: translations, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .rentalAgreement(rentalAgreement): + let (dict, fileReferences, translations) = rentalAgreement.serialize() + return InputSecureIdValueData(type: .secureValueTypeRentalAgreement, dict: dict, fileReferences: fileReferences, translationReferences: translations, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + case let .phone(phone): + return InputSecureIdValueData(type: .secureValueTypePhone, dict: nil, fileReferences: [], translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainPhone(phone: phone.phone)) + case let .email(email): + return InputSecureIdValueData(type: .secureValueTypeEmail, dict: nil, fileReferences: [], translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainEmail(email: email.email)) + } +} + +private func makeInputSecureValue(context: SecureIdAccessContext, value: SecureIdValue) -> Api.InputSecureValue? { + let inputData = inputSecureIdValueData(value: value) + + var secureData: Api.SecureData? + if let dict = inputData.dict { + guard let decryptedData = try? JSONSerialization.data(withJSONObject: dict, options: []) else { + return nil + } + guard let valueContext = generateSecureIdValueAccessContext() else { + return nil + } + guard let encryptedData = encryptedSecureValueData(context: context, valueContext: valueContext, data: decryptedData) else { + return nil + } + guard let checkValueContext = decryptedSecureValueAccessContext(context: context, encryptedSecret: encryptedData.encryptedSecret, decryptedDataHash: encryptedData.dataHash) else { + return nil + } + if checkValueContext != valueContext { + return nil + } + if let checkData = decryptedSecureValueData(context: checkValueContext, encryptedData: encryptedData.data, decryptedDataHash: encryptedData.dataHash) { + if checkData != decryptedData { + return nil + } + } else { + return nil + } + secureData = .secureData(data: Buffer(data: encryptedData.data), dataHash: Buffer(data: encryptedData.dataHash), secret: Buffer(data: encryptedData.encryptedSecret)) + } + + var flags: Int32 = 0 + + let files = inputData.fileReferences.map(apiInputSecretFile) + let translations = inputData.translationReferences.map(apiInputSecretFile) + + if secureData != nil { + flags |= 1 << 0 + } + if inputData.frontSideReference != nil { + flags |= 1 << 1 + } + if inputData.backSideReference != nil { + flags |= 1 << 2 + } + if inputData.selfieReference != nil { + flags |= 1 << 3 + } + if !files.isEmpty { + flags |= 1 << 4 + } + if !translations.isEmpty { + flags |= 1 << 6 + } + if inputData.publicData != nil { + flags |= 1 << 5 + } + + return Api.InputSecureValue.inputSecureValue(flags: flags, type: inputData.type, data: secureData, frontSide: inputData.frontSideReference.flatMap(apiInputSecretFile), reverseSide: inputData.backSideReference.flatMap(apiInputSecretFile), selfie: inputData.selfieReference.flatMap(apiInputSecretFile), translation: translations, files: files, plainData: inputData.publicData) +} + +public func saveSecureIdValue(postbox: Postbox, network: Network, context: SecureIdAccessContext, value: SecureIdValue, uploadedFiles: [Data: Data]) -> Signal { + let delete = deleteSecureIdValues(network: network, keys: Set([value.key])) + |> mapError { _ -> SaveSecureIdValueError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + + guard let inputValue = makeInputSecureValue(context: context, value: value) else { + return .fail(.generic) + } + let save = network.request(Api.functions.account.saveSecureValue(value: inputValue, secureSecretId: context.id)) + |> mapError { error -> SaveSecureIdValueError in + switch error.errorDescription { + case "PHONE_VERIFICATION_NEEDED", "EMAIL_VERIFICATION_NEEDED": + return .verificationRequired + case "APP_VERSION_OUTDATED": + return .versionOutdated + default: + return .generic + } + } + |> mapToSignal { result -> Signal in + guard let parsedValue = parseSecureValue(context: context, value: result, errors: []) else { + return .fail(.generic) + } + + for file in parsedValue.valueWithContext.value.fileReferences { + switch file { + case let .remote(file): + if let data = uploadedFiles[file.fileHash] { + postbox.mediaBox.storeResourceData(SecureFileMediaResource(file: file).id, data: data) + } + case .uploaded: + break + } + } + + return .single(parsedValue.valueWithContext) + } + + return delete |> then(save) +} + +public enum DeleteSecureIdValueError { + case generic + case versionOutdated +} + +public func deleteSecureIdValues(network: Network, keys: Set) -> Signal { + return network.request(Api.functions.account.deleteSecureValue(types: keys.map(apiSecureValueType(key:)))) + |> mapError { error -> DeleteSecureIdValueError in + switch error.errorDescription { + case "APP_VERSION_OUTDATED": + return .versionOutdated + default: + return .generic + } + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +public func dropSecureId(network: Network, currentPassword: String) -> Signal { + return twoStepAuthData(network) + |> mapError { _ -> AuthorizationPasswordVerificationError in + return .generic + } + |> mapToSignal { authData -> Signal in + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) + if let kdfResult = kdfResult { + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + } else { + return .fail(.generic) + } + } else { + checkPassword = .inputCheckPasswordEmpty + } + + let settings = network.request(Api.functions.account.getPasswordSettings(password: checkPassword), automaticFloodWait: false) + |> mapError { error in + return AuthorizationPasswordVerificationError.generic + } + + return settings + |> mapToSignal { value -> Signal in + switch value { + case .passwordSettings: + var flags: Int32 = 0 + flags |= (1 << 2) + return network.request(Api.functions.account.updatePasswordSettings(password: .inputCheckPasswordEmpty, newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSettings: nil)), automaticFloodWait: false) + |> map { _ in } + |> mapError { _ in + return AuthorizationPasswordVerificationError.generic + } + } + } + } +} + +public enum GetAllSecureIdValuesError { + case generic + case versionOutdated +} + +public struct EncryptedAllSecureIdValues { + fileprivate let values: [Api.SecureValue] +} + +public func getAllSecureIdValues(network: Network) -> Signal { + return network.request(Api.functions.account.getAllSecureValues()) + |> mapError { error -> GetAllSecureIdValuesError in + switch error.errorDescription { + case "APP_VERSION_OUTDATED": + return .versionOutdated + default: + return .generic + } + } + |> map { result in + return EncryptedAllSecureIdValues(values: result) + } +} + +public func decryptedAllSecureIdValues(context: SecureIdAccessContext, encryptedValues: EncryptedAllSecureIdValues) -> [SecureIdValueWithContext] { + var values: [SecureIdValueWithContext] = [] + for value in encryptedValues.values { + if let parsedValue = parseSecureValue(context: context, value: value, errors: []) { + values.append(parsedValue.valueWithContext) + } + } + return values +} diff --git a/submodules/TelegramCore/TelegramCore/SavedStickerItem.swift b/submodules/TelegramCore/TelegramCore/SavedStickerItem.swift new file mode 100644 index 0000000000..7b58381d05 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SavedStickerItem.swift @@ -0,0 +1,30 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class SavedStickerItem: OrderedItemListEntryContents, Equatable { + public let file: TelegramMediaFile + public let stringRepresentations: [String] + + init(file: TelegramMediaFile, stringRepresentations: [String]) { + self.file = file + self.stringRepresentations = stringRepresentations + } + + public init(decoder: PostboxDecoder) { + self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile + self.stringRepresentations = decoder.decodeStringArrayForKey("sr") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.file, forKey: "f") + encoder.encodeStringArray(self.stringRepresentations, forKey: "sr") + } + + public static func ==(lhs: SavedStickerItem, rhs: SavedStickerItem) -> Bool { + return lhs.file.isEqual(to: rhs.file) && lhs.stringRepresentations == rhs.stringRepresentations + } +} diff --git a/submodules/TelegramCore/TelegramCore/SearchBotsConfiguration.swift b/submodules/TelegramCore/TelegramCore/SearchBotsConfiguration.swift new file mode 100644 index 0000000000..31d41bac83 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SearchBotsConfiguration.swift @@ -0,0 +1,67 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public struct SearchBotsConfiguration: Equatable, PreferencesEntry { + public let imageBotUsername: String? + public let gifBotUsername: String? + public let venueBotUsername: String? + + public static var defaultValue: SearchBotsConfiguration { + return SearchBotsConfiguration(imageBotUsername: "bing", gifBotUsername: "gif", venueBotUsername: "foursquare") + } + + init(imageBotUsername: String?, gifBotUsername: String?, venueBotUsername: String?) { + self.imageBotUsername = imageBotUsername + self.gifBotUsername = gifBotUsername + self.venueBotUsername = venueBotUsername + } + + public init(decoder: PostboxDecoder) { + self.imageBotUsername = decoder.decodeOptionalStringForKey("img") + self.gifBotUsername = decoder.decodeOptionalStringForKey("gif") + self.venueBotUsername = decoder.decodeOptionalStringForKey("venue") + } + + public func encode(_ encoder: PostboxEncoder) { + if let imageBotUsername = self.imageBotUsername { + encoder.encodeString(imageBotUsername, forKey: "img") + } else { + encoder.encodeNil(forKey: "img") + } + if let gifBotUsername = self.gifBotUsername { + encoder.encodeString(gifBotUsername, forKey: "gif") + } else { + encoder.encodeNil(forKey: "gif") + } + if let venueBotUsername = self.venueBotUsername { + encoder.encodeString(venueBotUsername, forKey: "venue") + } else { + encoder.encodeNil(forKey: "venue") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? SearchBotsConfiguration else { + return false + } + return self == to + } +} + +public func currentSearchBotsConfiguration(transaction: Transaction) -> SearchBotsConfiguration { + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration) as? SearchBotsConfiguration { + return entry + } else { + return SearchBotsConfiguration.defaultValue + } +} + +func updateSearchBotsConfiguration(transaction: Transaction, configuration: SearchBotsConfiguration) { + if !currentSearchBotsConfiguration(transaction: transaction).isEqual(to: configuration) { + transaction.setPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration, value: configuration) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SearchGroupMembers.swift b/submodules/TelegramCore/TelegramCore/SearchGroupMembers.swift new file mode 100644 index 0000000000..ffe2ee997e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SearchGroupMembers.swift @@ -0,0 +1,72 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private func searchLocalGroupMembers(postbox: Postbox, peerId: PeerId, query: String) -> Signal<[Peer], NoError> { + return peerParticipants(postbox: postbox, id: peerId) + |> map { peers -> [Peer] in + let normalizedQuery = query.lowercased() + + if normalizedQuery.isEmpty { + return peers + } + + return peers.filter { peer in + if peer.debugDisplayTitle.isEmpty { + return false + } + if peer.indexName.matchesByTokens(normalizedQuery) { + return true + } + if let addressName = peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { + return true + } + return false + } + } +} + +public func searchGroupMembers(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, query: String) -> Signal<[Peer], NoError> { + if peerId.namespace == Namespaces.Peer.CloudChannel && !query.isEmpty { + return searchLocalGroupMembers(postbox: postbox, peerId: peerId, query: query) + |> mapToSignal { local -> Signal<[Peer], NoError> in + let localResult: Signal<[Peer], NoError> + if local.isEmpty { + localResult = .complete() + } else { + localResult = .single(local) + } + return localResult + |> then( + channelMembers(postbox: postbox, network: network, accountPeerId: accountPeerId, peerId: peerId, category: .recent(.search(query))) + |> map { participants -> [Peer] in + var result: [Peer] = local + let existingIds = Set(local.map { $0.id }) + let filtered: [Peer] + if let participants = participants { + filtered = participants.map({ $0.peer }).filter({ peer in + if existingIds.contains(peer.id) { + return false + } + if peer.debugDisplayTitle.isEmpty { + return false + } + return true + }) + } else { + filtered = [] + } + result.append(contentsOf: filtered) + return result + } + ) + } + } else { + return searchLocalGroupMembers(postbox: postbox, peerId: peerId, query: query) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SearchMessages.swift b/submodules/TelegramCore/TelegramCore/SearchMessages.swift new file mode 100644 index 0000000000..004020cd3c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SearchMessages.swift @@ -0,0 +1,664 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum SearchMessagesLocation: Equatable { + case general + case group(PeerGroupId) + case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?) +} + +private struct SearchMessagesPeerState: Equatable { + let messages: [Message] + let readStates: [PeerId: CombinedPeerReadState] + let totalCount: Int32 + let completed: Bool + let nextRate: Int32? + + static func ==(lhs: SearchMessagesPeerState, rhs: SearchMessagesPeerState) -> Bool { + if lhs.totalCount != rhs.totalCount { + return false + } + if lhs.completed != rhs.completed { + return false + } + if lhs.messages.count != rhs.messages.count { + return false + } + for i in 0 ..< lhs.messages.count { + if lhs.messages[i].id != rhs.messages[i].id { + return false + } + } + if lhs.nextRate != rhs.nextRate { + return false + } + return true + } +} + +public struct SearchMessagesResult { + public let messages: [Message] + public let readStates: [PeerId: CombinedPeerReadState] + public let totalCount: Int32 + public let completed: Bool +} + +public struct SearchMessagesState: Equatable { + fileprivate let main: SearchMessagesPeerState + fileprivate let additional: SearchMessagesPeerState? +} + +private func mergedState(transaction: Transaction, state: SearchMessagesPeerState?, result: Api.messages.Messages?) -> SearchMessagesPeerState? { + guard let result = result else { + return state + } + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + let totalCount: Int32 + let nextRate: Int32? + switch result { + case let .channelMessages(_, _, count, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + totalCount = count + nextRate = nil + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + totalCount = Int32(messages.count) + nextRate = nil + case let .messagesSlice(_, count, apiNextRate, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + totalCount = count + nextRate = apiNextRate + case .messagesNotModified: + messages = [] + chats = [] + users = [] + totalCount = 0 + nextRate = nil + } + + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + var peerIdsSet: Set = Set() + var readStates: [PeerId: CombinedPeerReadState] = [:] + + var renderedMessages: [Message] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + renderedMessages.append(renderedMessage) + peerIdsSet.insert(message.id.peerId) + } + } + + for peerId in peerIdsSet { + if let readState = transaction.getCombinedPeerReadState(peerId) { + readStates[peerId] = readState + } + } + + renderedMessages.sort(by: { lhs, rhs in + return lhs.index > rhs.index + }) + + let completed = renderedMessages.isEmpty + if let previous = state { + var currentIds = Set() + var mergedMessages: [Message] = [] + for message in previous.messages { + if currentIds.contains(message.id) { + continue + } + currentIds.insert(message.id) + mergedMessages.append(message) + } + for message in renderedMessages { + if currentIds.contains(message.id) { + continue + } + currentIds.insert(message.id) + mergedMessages.append(message) + } + mergedMessages.sort(by: { lhs, rhs in + return lhs.index > rhs.index + }) + return SearchMessagesPeerState(messages: mergedMessages, readStates: readStates, totalCount: completed ? Int32(mergedMessages.count) : totalCount, completed: completed, nextRate: nextRate) + } else { + return SearchMessagesPeerState(messages: renderedMessages, readStates: readStates, totalCount: completed ? Int32(renderedMessages.count) : totalCount, completed: completed, nextRate: nextRate) + } +} + +private func mergedResult(_ state: SearchMessagesState) -> SearchMessagesResult { + var messages: [Message] = state.main.messages + if let additional = state.additional { + if state.main.completed { + messages.append(contentsOf: additional.messages) + } else if let lastMessage = state.main.messages.last { + let earliestIndex = lastMessage.index + messages.append(contentsOf: additional.messages.filter({ $0.index > earliestIndex })) + } + } + messages.sort(by: { lhs, rhs in + return lhs.index > rhs.index + }) + + var readStates: [PeerId: CombinedPeerReadState] = [:] + for message in messages { + let readState = state.main.readStates[message.id.peerId] ?? state.additional?.readStates[message.id.peerId] + if let readState = readState { + readStates[message.id.peerId] = readState + } + } + + return SearchMessagesResult(messages: messages, readStates: readStates, totalCount: state.main.totalCount + (state.additional?.totalCount ?? 0), completed: state.main.completed && (state.additional?.completed ?? true)) +} + +public func searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> { + let remoteSearchResult: Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> + switch location { + case let .peer(peerId, fromId, tags): + if peerId.namespace == Namespaces.Peer.SecretChat { + return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in + var readStates: [PeerId: CombinedPeerReadState] = [:] + if let readState = transaction.getCombinedPeerReadState(peerId) { + readStates[peerId] = readState + } + let result = transaction.searchMessages(peerId: peerId, query: query, tags: tags) + return (SearchMessagesResult(messages: result, readStates: readStates, totalCount: Int32(result.count), completed: true), SearchMessagesState(main: SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true, nextRate: nil), additional: nil)) + } + } + + let filter: Api.MessagesFilter + + if let tags = tags { + if tags.contains(.file) { + filter = .inputMessagesFilterDocument + } else if tags.contains(.music) { + filter = .inputMessagesFilterMusic + } else if tags.contains(.webPage) { + filter = .inputMessagesFilterUrl + } else { + filter = .inputMessagesFilterEmpty + } + } else { + filter = .inputMessagesFilterEmpty + } + remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?)? in + guard let peer = transaction.getPeer(peerId) else { + return nil + } + var additionalPeer: Peer? + if let _ = peer as? TelegramChannel, let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference { + additionalPeer = transaction.getPeer(migrationReference.maxMessageId.peerId) + } + if let fromId = fromId { + return (peer: peer, additionalPeer: additionalPeer, from: transaction.getPeer(fromId)) + } + return (peer: peer, additionalPeer: additionalPeer, from: nil) + } + |> mapToSignal { values -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in + guard let values = values else { + return .single((nil, nil)) + } + let peer = values.peer + guard let inputPeer = apiInputPeer(peer) else { + return .single((nil, nil)) + } + var fromInputUser: Api.InputUser? = nil + var flags: Int32 = 0 + if let from = values.from { + fromInputUser = apiInputUser(from) + if let _ = fromInputUser { + flags |= (1 << 0) + } + } + let peerMessages: Signal + if let completed = state?.main.completed, completed { + peerMessages = .single(nil) + } else { + let lowerBound = state?.main.messages.last.flatMap({ $0.index }) + peerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + } + let additionalPeerMessages: Signal + if let inputPeer = values.additionalPeer.flatMap(apiInputPeer) { + let mainCompleted = state?.main.completed ?? false + let hasAdditional = state?.additional != nil + if let completed = state?.additional?.completed, completed { + additionalPeerMessages = .single(nil) + } else if mainCompleted || !hasAdditional { + let lowerBound = state?.additional?.messages.last.flatMap({ $0.index }) + additionalPeerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + } else { + additionalPeerMessages = .single(nil) + } + } else { + additionalPeerMessages = .single(nil) + } + return combineLatest(peerMessages, additionalPeerMessages) + } + case let .group(groupId): + remoteSearchResult = .single((nil, nil)) + /*remoteSearchResult = account.network.request(Api.functions.channels.searchFeed(feedId: groupId.rawValue, q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64), automaticFloodWait: false) + |> mapError { _ in } |> map(Optional.init)*/ + case .general: + remoteSearchResult = account.postbox.transaction { transaction -> (Int32, MessageIndex?, Api.InputPeer) in + var lowerBound: MessageIndex? + if let state = state, let message = state.main.messages.last { + lowerBound = message.index + } + if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) { + return (state?.main.nextRate ?? 0, lowerBound, inputPeer) + } else { + return (0, lowerBound, .inputPeerEmpty) + } + } + |> mapToSignal { (nextRate, lowerBound, inputPeer) in + account.network.request(Api.functions.messages.searchGlobal(q: query, offsetRate: nextRate, offsetPeer: inputPeer, offsetId: lowerBound?.id.id ?? 0, limit: limit), automaticFloodWait: false) + |> map { result -> (Api.messages.Messages?, Api.messages.Messages?) in + return (result, nil) + } + |> `catch` { _ -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in + return .single((nil, nil)) + } + } + } + + return remoteSearchResult + |> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in + return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in + var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult) + if state?.additional == nil, case .general = location { + let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: nil) + var readStates: [PeerId: CombinedPeerReadState] = [:] + for message in secretMessages { + if let readState = transaction.getCombinedPeerReadState(message.id.peerId) { + readStates[message.id.peerId] = readState + } + } + additional = SearchMessagesPeerState(messages: secretMessages, readStates: readStates, totalCount: Int32(secretMessages.count), completed: true, nextRate: nil) + } + + let updatedState = SearchMessagesState(main: mergedState(transaction: transaction, state: state?.main, result: result) ?? SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true, nextRate: nil), additional: additional) + return (mergedResult(updatedState), updatedState) + } + } +} + +public func downloadMessage(postbox: Postbox, network: Network, messageId: MessageId) -> Signal { + return postbox.transaction { transaction -> Message? in + return transaction.getMessage(messageId) + } |> mapToSignal { message in + if let _ = message { + return .single(message) + } else { + return postbox.loadedPeerWithId(messageId.peerId) + |> mapToSignal { peer -> Signal in + let signal: Signal + if messageId.peerId.namespace == Namespaces.Peer.CloudChannel { + if let channel = apiInputChannel(peer) { + signal = network.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + } else { + signal = .complete() + } + } else { + signal = network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + } + + return signal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .single(nil) + } + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + + let postboxSignal = postbox.transaction { transaction -> Message? in + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + var renderedMessages: [Message] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + renderedMessages.append(renderedMessage) + } + } + + return renderedMessages.first + } + + return postboxSignal + } + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } + } +} + +func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource, message: MessageReference) -> Signal { + guard case let .message(peer, id, _, _, _) = message.content else { + return .single(nil) + } + let signal: Signal + if id.peerId.namespace == Namespaces.Peer.CloudChannel { + if let channel = peer.inputChannel { + signal = source.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(id: id.id)])) + } else { + signal = .fail(MTRpcError(errorCode: 400, errorDescription: "Peer Not Found")) + } + } else if id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup { + signal = source.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: id.id)])) + } else { + signal = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid Peer")) + } + + return signal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .single(nil) + } + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + + return postbox.transaction { transaction -> Message? in + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in + return updated + }) + + var renderedMessages: [Message] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message), case let .Id(updatedId) = message.id { + var addedExisting = false + if transaction.getMessage(updatedId) != nil { + transaction.updateMessage(updatedId, update: { _ in + return .update(message) + }) + if let updatedMessage = transaction.getMessage(updatedId) { + renderedMessages.append(updatedMessage) + addedExisting = true + } + } + + if !addedExisting, let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + renderedMessages.append(renderedMessage) + } + } + } + + return renderedMessages.first + } + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timestamp: Int32) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if peerId.namespace == Namespaces.Peer.SecretChat { + return .single(transaction.findClosestMessageIdByTimestamp(peerId: peerId, timestamp: timestamp)) + } else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + var secondaryIndex: Signal = .single(nil) + if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference, let secondaryPeer = transaction.getPeer(migrationReference.maxMessageId.peerId), let inputSecondaryPeer = apiInputPeer(secondaryPeer) { + secondaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputSecondaryPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0)) + |> map { result -> MessageIndex? in + let messages: [Api.Message] + switch result { + case let .messages(apiMessages, _, _): + messages = apiMessages + case let .channelMessages(_, _, _, apiMessages, _, _): + messages = apiMessages + case let .messagesSlice(_, _, _, apiMessages, _, _): + messages = apiMessages + case .messagesNotModified: + messages = [] + } + for message in messages { + if let message = StoreMessage(apiMessage: message) { + return message.index + } + } + return nil + } + |> `catch` { _ -> Signal in + return .single(nil) + } + } + let primaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0)) + |> map { result -> MessageIndex? in + let messages: [Api.Message] + switch result { + case let .messages(apiMessages, _, _): + messages = apiMessages + case let .channelMessages(_, _, _, apiMessages, _, _): + messages = apiMessages + case let .messagesSlice(_, _, _, apiMessages, _, _): + messages = apiMessages + case .messagesNotModified: + messages = [] + } + for message in messages { + if let message = StoreMessage(apiMessage: message) { + return message.index + } + } + return nil + } + |> `catch` { _ -> Signal in + return .single(nil) + } + return combineLatest(primaryIndex, secondaryIndex) + |> map { primaryIndex, secondaryIndex -> MessageId? in + if let primaryIndex = primaryIndex, let secondaryIndex = secondaryIndex { + if abs(primaryIndex.timestamp - timestamp) < abs(secondaryIndex.timestamp - timestamp) { + return primaryIndex.id + } else { + return secondaryIndex.id + } + } else if let primaryIndex = primaryIndex { + return primaryIndex.id + } else if let secondaryIndex = secondaryIndex { + return secondaryIndex.id + } else { + return nil + } + } + } else { + return .single(nil) + } + } |> switchToLatest +} + +enum UpdatedRemotePeerError { + case generic +} + +func updatedRemotePeer(postbox: Postbox, network: Network, peer: PeerReference) -> Signal { + if let inputUser = peer.inputUser { + return network.request(Api.functions.users.getUsers(id: [inputUser])) + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + |> mapToSignal { result -> Signal in + if let updatedPeer = result.first.flatMap(TelegramUser.init(user:)), updatedPeer.id == peer.id { + return postbox.transaction { transaction -> Peer in + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + return updatedPeer + } + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + } else { + return .fail(.generic) + } + } + } else if case let .group(id) = peer { + return network.request(Api.functions.messages.getChats(id: [id])) + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + |> mapToSignal { result -> Signal in + let chats: [Api.Chat] + switch result { + case let .chats(c): + chats = c + case let .chatsSlice(_, c): + chats = c + } + if let updatedPeer = chats.first.flatMap(parseTelegramGroupOrChannel), updatedPeer.id == peer.id { + return postbox.transaction { transaction -> Peer in + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + return updatedPeer + } + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + } else { + return .fail(.generic) + } + } + } else if let inputChannel = peer.inputChannel { + return network.request(Api.functions.channels.getChannels(id: [inputChannel])) + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + |> mapToSignal { result -> Signal in + let chats: [Api.Chat] + switch result { + case let .chats(c): + chats = c + case let .chatsSlice(_, c): + chats = c + } + if let updatedPeer = chats.first.flatMap(parseTelegramGroupOrChannel), updatedPeer.id == peer.id { + return postbox.transaction { transaction -> Peer in + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + return updatedPeer + } + |> mapError { _ -> UpdatedRemotePeerError in + return .generic + } + } else { + return .fail(.generic) + } + } + } else { + return .fail(.generic) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SearchPeers.swift b/submodules/TelegramCore/TelegramCore/SearchPeers.swift new file mode 100644 index 0000000000..5a80711c65 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SearchPeers.swift @@ -0,0 +1,117 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct FoundPeer: Equatable { + public let peer: Peer + public let subscribers: Int32? + + public init(peer: Peer, subscribers: Int32?) { + self.peer = peer + self.subscribers = subscribers + } + + public static func ==(lhs: FoundPeer, rhs: FoundPeer) -> Bool { + return lhs.peer.isEqual(rhs.peer) && lhs.subscribers == rhs.subscribers + } +} + +public func searchPeers(account: Account, query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> { + let searchResult = account.network.request(Api.functions.contacts.search(q: query, limit: 20), automaticFloodWait: false) + |> map(Optional.init) + |> `catch` { _ in + return Signal.single(nil) + } + let processedSearchResult = searchResult + |> mapToSignal { result -> Signal<([FoundPeer], [FoundPeer]), NoError> in + if let result = result { + switch result { + case let .found(myResults, results, chats, users): + return account.postbox.transaction { transaction -> ([FoundPeer], [FoundPeer]) in + var peers: [PeerId: Peer] = [:] + var subscribers: [PeerId: Int32] = [:] + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + switch chat { + /*feed*/ + case let .channel(channel): + if let participantsCount = channel.participantsCount { + subscribers[groupOrChannel.id] = participantsCount + } + default: + break + } + } + } + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in + return updated + }) + + var renderedMyPeers: [FoundPeer] = [] + for result in myResults { + let peerId: PeerId + switch result { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + if let peer = peers[peerId] { + if let group = peer as? TelegramGroup, group.migrationReference != nil { + continue + } + renderedMyPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) + } + } + + var renderedPeers: [FoundPeer] = [] + for result in results { + let peerId: PeerId + switch result { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + if let peer = peers[peerId] { + if let group = peer as? TelegramGroup, group.migrationReference != nil { + continue + } + renderedPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) + } + } + + return (renderedMyPeers, renderedPeers) + } + } + } else { + return .single(([], [])) + } + } + + return processedSearchResult +} + diff --git a/submodules/TelegramCore/TelegramCore/SearchStickers.swift b/submodules/TelegramCore/TelegramCore/SearchStickers.swift new file mode 100644 index 0000000000..08ed9c9528 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SearchStickers.swift @@ -0,0 +1,306 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public final class FoundStickerItem: Equatable { + public let file: TelegramMediaFile + public let stringRepresentations: [String] + + public init(file: TelegramMediaFile, stringRepresentations: [String]) { + self.file = file + self.stringRepresentations = stringRepresentations + } + + public static func ==(lhs: FoundStickerItem, rhs: FoundStickerItem) -> Bool { + if !lhs.file.isEqual(to: rhs.file) { + return false + } + if lhs.stringRepresentations != rhs.stringRepresentations { + return false + } + return true + } +} + +extension MutableCollection { + mutating func shuffle() { + let c = count + guard c > 1 else { return } + for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) { + let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount))) + let i = index(firstUnshuffled, offsetBy: d) + swapAt(firstUnshuffled, i) + } + } +} + +extension Sequence { + func shuffled() -> [Element] { + var result = Array(self) + result.shuffle() + return result + } +} + +final class CachedStickerQueryResult: PostboxCoding { + let items: [TelegramMediaFile] + let hash: Int32 + + init(items: [TelegramMediaFile], hash: Int32) { + self.items = items + self.hash = hash + } + + init(decoder: PostboxDecoder) { + self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! TelegramMediaFile } + self.hash = decoder.decodeInt32ForKey("h", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.items, forKey: "it") + encoder.encodeInt32(self.hash, forKey: "h") + } + + static func cacheKey(_ query: String) -> ValueBoxKey { + let key = ValueBoxKey(query) + return key + } +} + +private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200) + +public struct SearchStickersScope: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let installed = SearchStickersScope(rawValue: 1 << 0) + public static let remote = SearchStickersScope(rawValue: 1 << 1) +} + +public func searchStickers(account: Account, query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<[FoundStickerItem], NoError> { + if scope.isEmpty { + return .single([]) + } + return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?) in + var result: [FoundStickerItem] = [] + if scope.contains(.installed) { + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) { + if let item = entry.contents as? SavedStickerItem { + for representation in item.stringRepresentations { + if representation == query { + result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations)) + break + } + } + } + } + + let currentItems = Set(result.map { $0.file.fileId }) + var recentItems: [TelegramMediaFile] = [] + var recentItemsIds = Set() + var matchingRecentItemsIds = Set() + + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentStickers) { + if let item = entry.contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile { + if !currentItems.contains(file.fileId) { + for case let .Sticker(sticker) in file.attributes { + if sticker.displayText == query { + matchingRecentItemsIds.insert(file.fileId) + } + recentItemsIds.insert(file.fileId) + recentItems.append(file) + break + } + } + } + } + + var installed: [FoundStickerItem] = [] + for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, query: .exact(ValueBoxKey(query))) { + if let item = item as? StickerPackItem { + if !currentItems.contains(item.file.fileId) { + var stringRepresentations: [String] = [] + for key in item.indexKeys { + key.withDataNoCopy { data in + if let string = String(data: data, encoding: .utf8) { + stringRepresentations.append(string) + } + } + } + if !recentItemsIds.contains(item.file.fileId) { + installed.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) + } else { + matchingRecentItemsIds.insert(item.file.fileId) + } + } + } + } + + for file in recentItems { + if matchingRecentItemsIds.contains(file.fileId) { + result.append(FoundStickerItem(file: file, stringRepresentations: [query])) + } + } + + result.append(contentsOf: installed) + } + + let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query))) as? CachedStickerQueryResult + + return (result, cached) + } |> mapToSignal { localItems, cached -> Signal<[FoundStickerItem], NoError> in + var tempResult: [FoundStickerItem] = localItems + if !scope.contains(.remote) { + return .single(tempResult) + } + let currentItems = Set(localItems.map { $0.file.fileId }) + if let cached = cached { + for file in cached.items { + if !currentItems.contains(file.fileId) { + tempResult.append(FoundStickerItem(file: file, stringRepresentations: [])) + } + } + } + + let remote = account.network.request(Api.functions.messages.getStickers(emoticon: query, hash: cached?.hash ?? 0)) + |> `catch` { _ -> Signal in + return .single(.stickersNotModified) + } + |> mapToSignal { result -> Signal<[FoundStickerItem], NoError> in + return account.postbox.transaction { transaction -> [FoundStickerItem] in + switch result { + case let .stickers(hash, stickers): + var items: [FoundStickerItem] = localItems + let currentItems = Set(items.map { $0.file.fileId }) + + var files: [TelegramMediaFile] = [] + for sticker in stickers { + if let file = telegramMediaFileFromApiDocument(sticker), let id = file.id { + files.append(file) + if !currentItems.contains(id) { + items.append(FoundStickerItem(file: file, stringRepresentations: [])) + } + } + } + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: CachedStickerQueryResult(items: files, hash: hash), collectionSpec: collectionSpec) + + return items + case .stickersNotModified: + break + } + return tempResult + } + } + return .single(tempResult) + |> then(remote) + } +} + +public struct FoundStickerSets { + public let infos: [(ItemCollectionId, ItemCollectionInfo, ItemCollectionItem?, Bool)] + public let entries: [ItemCollectionViewEntry] + public init(infos: [(ItemCollectionId, ItemCollectionInfo, ItemCollectionItem?, Bool)] = [], entries: [ItemCollectionViewEntry] = []) { + self.infos = infos + self.entries = entries + } + + public func withUpdatedInfosAndEntries(infos: [(ItemCollectionId, ItemCollectionInfo, ItemCollectionItem?, Bool)], entries: [ItemCollectionViewEntry]) -> FoundStickerSets { + let infoResult = self.infos + infos + let entriesResult = self.entries + entries + return FoundStickerSets(infos: infoResult, entries: entriesResult) + } + + public func merge(with other: FoundStickerSets) -> FoundStickerSets { + return FoundStickerSets(infos: self.infos + other.infos, entries: self.entries + other.entries) + } +} + +public func searchStickerSetsRemotely(network: Network, query: String) -> Signal { + return network.request(Api.functions.messages.searchStickerSets(flags: 0, q: query, hash: 0)) + |> mapError {_ in} + |> mapToSignal { value in + var index: Int32 = 1000 + switch value { + case let .foundStickerSets(_, sets: sets): + var result = FoundStickerSets() + for set in sets { + let parsed = parsePreviewStickerSet(set) + let values = parsed.1.map({ ItemCollectionViewEntry(index: ItemCollectionViewEntryIndex(collectionIndex: index, collectionId: parsed.0.id, itemIndex: $0.index), item: $0) }) + result = result.withUpdatedInfosAndEntries(infos: [(parsed.0.id, parsed.0, parsed.1.first, false)], entries: values) + index += 1 + } + return .single(result) + default: + break + } + + return .complete() + } + |> `catch` { _ -> Signal in + return .single(FoundStickerSets()) + } +} + +public func searchStickerSets(postbox: Postbox, query: String) -> Signal { + return postbox.transaction { transaction -> Signal in + let infos = transaction.getItemCollectionsInfos(namespace: Namespaces.ItemCollection.CloudStickerPacks) + + var collections: [(ItemCollectionId, ItemCollectionInfo)] = [] + var topItems: [ItemCollectionId: ItemCollectionItem] = [:] + var entries: [ItemCollectionViewEntry] = [] + for info in infos { + if let info = info.1 as? StickerPackCollectionInfo { + let split = info.title.split(separator: " ") + if !split.filter({$0.lowercased().hasPrefix(query.lowercased())}).isEmpty || info.shortName.lowercased().hasPrefix(query.lowercased()) { + collections.append((info.id, info)) + } + } + } + var index: Int32 = 0 + + for info in collections { + let items = transaction.getItemCollectionItems(collectionId: info.0) + let values = items.map({ ItemCollectionViewEntry(index: ItemCollectionViewEntryIndex(collectionIndex: index, collectionId: info.0, itemIndex: $0.index), item: $0) }) + entries.append(contentsOf: values) + if let first = items.first { + topItems[info.0] = first + } + index += 1 + } + + let result = FoundStickerSets(infos: collections.map { ($0.0, $0.1, topItems[$0.0], true) }, entries: entries) + + return .single(result) + } |> switchToLatest +} + +public func searchGifs(account: Account, query: String) -> Signal { + return resolvePeerByName(account: account, name: "gif") + |> filter { $0 != nil } + |> map { $0! } + |> mapToSignal { peerId -> Signal in + return account.postbox.loadedPeerWithId(peerId) + } + |> mapToSignal { peer -> Signal in + return requestChatContextResults(account: account, botId: peer.id, peerId: account.peerId, query: query, offset: "") + } +} + +extension TelegramMediaFile { + var stickerString: String? { + for attr in attributes { + if case let .Sticker(displayText, _, _) = attr { + return displayText + } + } + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretApiLayer46.swift b/submodules/TelegramCore/TelegramCore/SecretApiLayer46.swift new file mode 100644 index 0000000000..f9d68ce39c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretApiLayer46.swift @@ -0,0 +1,1506 @@ + + +fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { + var dict: [Int32 : (BufferReader) -> Any?] = [:] + dict[-1471112230] = { return $0.readInt32() } + dict[570911930] = { return $0.readInt64() } + dict[571523412] = { return $0.readDouble() } + dict[-1255641564] = { return parseString($0) } + dict[-1586283796] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionSetMessageTTL($0) } + dict[206520510] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionReadMessages($0) } + dict[1700872964] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionDeleteMessages($0) } + dict[-1967000459] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionScreenshotMessages($0) } + dict[1729750108] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionFlushHistory($0) } + dict[-217806717] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionNotifyLayer($0) } + dict[1360072880] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionResend($0) } + dict[-204906213] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionRequestKey($0) } + dict[1877046107] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionAcceptKey($0) } + dict[-586814357] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionAbortKey($0) } + dict[-332526693] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionCommitKey($0) } + dict[-1473258141] = { return SecretApi46.DecryptedMessageAction.parse_decryptedMessageActionNoop($0) } + dict[236446268] = { return SecretApi46.PhotoSize.parse_photoSizeEmpty($0) } + dict[2009052699] = { return SecretApi46.PhotoSize.parse_photoSize($0) } + dict[-374917894] = { return SecretApi46.PhotoSize.parse_photoCachedSize($0) } + dict[2086234950] = { return SecretApi46.FileLocation.parse_fileLocationUnavailable($0) } + dict[1406570614] = { return SecretApi46.FileLocation.parse_fileLocation($0) } + dict[467867529] = { return SecretApi46.DecryptedMessageLayer.parse_decryptedMessageLayer($0) } + dict[1930838368] = { return SecretApi46.DecryptedMessage.parse_decryptedMessageService($0) } + dict[917541342] = { return SecretApi46.DecryptedMessage.parse_decryptedMessage($0) } + dict[1815593308] = { return SecretApi46.DocumentAttribute.parse_documentAttributeImageSize($0) } + dict[297109817] = { return SecretApi46.DocumentAttribute.parse_documentAttributeAnimated($0) } + dict[1494273227] = { return SecretApi46.DocumentAttribute.parse_documentAttributeVideo($0) } + dict[358154344] = { return SecretApi46.DocumentAttribute.parse_documentAttributeFilename($0) } + dict[978674434] = { return SecretApi46.DocumentAttribute.parse_documentAttributeSticker($0) } + dict[-1739392570] = { return SecretApi46.DocumentAttribute.parse_documentAttributeAudio($0) } + dict[-2044933984] = { return SecretApi46.InputStickerSet.parse_inputStickerSetShortName($0) } + dict[-4838507] = { return SecretApi46.InputStickerSet.parse_inputStickerSetEmpty($0) } + dict[-1148011883] = { return SecretApi46.MessageEntity.parse_messageEntityUnknown($0) } + dict[-100378723] = { return SecretApi46.MessageEntity.parse_messageEntityMention($0) } + dict[1868782349] = { return SecretApi46.MessageEntity.parse_messageEntityHashtag($0) } + dict[1827637959] = { return SecretApi46.MessageEntity.parse_messageEntityBotCommand($0) } + dict[1859134776] = { return SecretApi46.MessageEntity.parse_messageEntityUrl($0) } + dict[1692693954] = { return SecretApi46.MessageEntity.parse_messageEntityEmail($0) } + dict[-1117713463] = { return SecretApi46.MessageEntity.parse_messageEntityBold($0) } + dict[-2106619040] = { return SecretApi46.MessageEntity.parse_messageEntityItalic($0) } + dict[681706865] = { return SecretApi46.MessageEntity.parse_messageEntityCode($0) } + dict[1938967520] = { return SecretApi46.MessageEntity.parse_messageEntityPre($0) } + dict[1990644519] = { return SecretApi46.MessageEntity.parse_messageEntityTextUrl($0) } + dict[144661578] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaEmpty($0) } + dict[893913689] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaGeoPoint($0) } + dict[1485441687] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaContact($0) } + dict[1474341323] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaAudio($0) } + dict[-90853155] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaExternalDocument($0) } + dict[-235238024] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaPhoto($0) } + dict[2063502050] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaDocument($0) } + dict[-1760785394] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaVideo($0) } + dict[-1978796689] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaVenue($0) } + dict[-452652584] = { return SecretApi46.DecryptedMessageMedia.parse_decryptedMessageMediaWebPage($0) } + return dict +}() + +public struct SecretApi46 { + public static func parse(_ buffer: Buffer) -> Any? { + let reader = BufferReader(buffer) + if let signature = reader.readInt32() { + return parse(reader, signature: signature) + } + return nil + } + + fileprivate static func parse(_ reader: BufferReader, signature: Int32) -> Any? { + if let parser = parsers[signature] { + return parser(reader) + } + else { + Logger.shared.log("TL", "Type constructor \(String(signature, radix: 16, uppercase: false)) not found") + return nil + } + } + + fileprivate static func parseVector(_ reader: BufferReader, elementSignature: Int32, elementType: T.Type) -> [T]? { + if let count = reader.readInt32() { + var array = [T]() + var i: Int32 = 0 + while i < count { + var signature = elementSignature + if elementSignature == 0 { + if let unboxedSignature = reader.readInt32() { + signature = unboxedSignature + } + else { + return nil + } + } + if let item = SecretApi46.parse(reader, signature: signature) as? T { + array.append(item) + } + else { + return nil + } + i += 1 + } + return array + } + return nil + } + + public static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) { + switch object { + case let _1 as SecretApi46.DecryptedMessageAction: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.PhotoSize: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.FileLocation: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.DecryptedMessageLayer: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.DecryptedMessage: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.DocumentAttribute: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.InputStickerSet: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.MessageEntity: + _1.serialize(buffer, boxed) + case let _1 as SecretApi46.DecryptedMessageMedia: + _1.serialize(buffer, boxed) + default: + break + } + } + + public enum DecryptedMessageAction { + case decryptedMessageActionSetMessageTTL(ttlSeconds: Int32) + case decryptedMessageActionReadMessages(randomIds: [Int64]) + case decryptedMessageActionDeleteMessages(randomIds: [Int64]) + case decryptedMessageActionScreenshotMessages(randomIds: [Int64]) + case decryptedMessageActionFlushHistory + case decryptedMessageActionNotifyLayer(layer: Int32) + case decryptedMessageActionResend(startSeqNo: Int32, endSeqNo: Int32) + case decryptedMessageActionRequestKey(exchangeId: Int64, gA: Buffer) + case decryptedMessageActionAcceptKey(exchangeId: Int64, gB: Buffer, keyFingerprint: Int64) + case decryptedMessageActionAbortKey(exchangeId: Int64) + case decryptedMessageActionCommitKey(exchangeId: Int64, keyFingerprint: Int64) + case decryptedMessageActionNoop + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageActionSetMessageTTL(let ttlSeconds): + if boxed { + buffer.appendInt32(-1586283796) + } + serializeInt32(ttlSeconds, buffer: buffer, boxed: false) + break + case .decryptedMessageActionReadMessages(let randomIds): + if boxed { + buffer.appendInt32(206520510) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionDeleteMessages(let randomIds): + if boxed { + buffer.appendInt32(1700872964) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionScreenshotMessages(let randomIds): + if boxed { + buffer.appendInt32(-1967000459) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionFlushHistory: + if boxed { + buffer.appendInt32(1729750108) + } + + break + case .decryptedMessageActionNotifyLayer(let layer): + if boxed { + buffer.appendInt32(-217806717) + } + serializeInt32(layer, buffer: buffer, boxed: false) + break + case .decryptedMessageActionResend(let startSeqNo, let endSeqNo): + if boxed { + buffer.appendInt32(1360072880) + } + serializeInt32(startSeqNo, buffer: buffer, boxed: false) + serializeInt32(endSeqNo, buffer: buffer, boxed: false) + break + case .decryptedMessageActionRequestKey(let exchangeId, let gA): + if boxed { + buffer.appendInt32(-204906213) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeBytes(gA, buffer: buffer, boxed: false) + break + case .decryptedMessageActionAcceptKey(let exchangeId, let gB, let keyFingerprint): + if boxed { + buffer.appendInt32(1877046107) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeBytes(gB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .decryptedMessageActionAbortKey(let exchangeId): + if boxed { + buffer.appendInt32(-586814357) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + break + case .decryptedMessageActionCommitKey(let exchangeId, let keyFingerprint): + if boxed { + buffer.appendInt32(-332526693) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .decryptedMessageActionNoop: + if boxed { + buffer.appendInt32(-1473258141) + } + + break + } + } + + fileprivate static func parse_decryptedMessageActionSetMessageTTL(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionSetMessageTTL(ttlSeconds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionReadMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi46.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionReadMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionDeleteMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi46.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionDeleteMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionScreenshotMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi46.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionScreenshotMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionFlushHistory(_ reader: BufferReader) -> DecryptedMessageAction? { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionFlushHistory + } + fileprivate static func parse_decryptedMessageActionNotifyLayer(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionNotifyLayer(layer: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionResend(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionResend(startSeqNo: _1!, endSeqNo: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionRequestKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionRequestKey(exchangeId: _1!, gA: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionAcceptKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionAcceptKey(exchangeId: _1!, gB: _2!, keyFingerprint: _3!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionAbortKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionAbortKey(exchangeId: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionCommitKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionCommitKey(exchangeId: _1!, keyFingerprint: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionNoop(_ reader: BufferReader) -> DecryptedMessageAction? { + return SecretApi46.DecryptedMessageAction.decryptedMessageActionNoop + } + + } + + public enum PhotoSize { + case photoSizeEmpty(type: String) + case photoSize(type: String, location: SecretApi46.FileLocation, w: Int32, h: Int32, size: Int32) + case photoCachedSize(type: String, location: SecretApi46.FileLocation, w: Int32, h: Int32, bytes: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photoSizeEmpty(let type): + if boxed { + buffer.appendInt32(236446268) + } + serializeString(type, buffer: buffer, boxed: false) + break + case .photoSize(let type, let location, let w, let h, let size): + if boxed { + buffer.appendInt32(2009052699) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + break + case .photoCachedSize(let type, let location, let w, let h, let bytes): + if boxed { + buffer.appendInt32(-374917894) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_photoSizeEmpty(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi46.PhotoSize.photoSizeEmpty(type: _1!) + } + else { + return nil + } + } + fileprivate static func parse_photoSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi46.FileLocation? + if let signature = reader.readInt32() { + _2 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi46.PhotoSize.photoSize(type: _1!, location: _2!, w: _3!, h: _4!, size: _5!) + } + else { + return nil + } + } + fileprivate static func parse_photoCachedSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi46.FileLocation? + if let signature = reader.readInt32() { + _2 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi46.PhotoSize.photoCachedSize(type: _1!, location: _2!, w: _3!, h: _4!, bytes: _5!) + } + else { + return nil + } + } + + } + + public enum FileLocation { + case fileLocationUnavailable(volumeId: Int64, localId: Int32, secret: Int64) + case fileLocation(dcId: Int32, volumeId: Int64, localId: Int32, secret: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileLocationUnavailable(let volumeId, let localId, let secret): + if boxed { + buffer.appendInt32(2086234950) + } + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + serializeInt64(secret, buffer: buffer, boxed: false) + break + case .fileLocation(let dcId, let volumeId, let localId, let secret): + if boxed { + buffer.appendInt32(1406570614) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + serializeInt64(secret, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_fileLocationUnavailable(_ reader: BufferReader) -> FileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi46.FileLocation.fileLocationUnavailable(volumeId: _1!, localId: _2!, secret: _3!) + } + else { + return nil + } + } + fileprivate static func parse_fileLocation(_ reader: BufferReader) -> FileLocation? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int64? + _4 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi46.FileLocation.fileLocation(dcId: _1!, volumeId: _2!, localId: _3!, secret: _4!) + } + else { + return nil + } + } + + } + + public enum DecryptedMessageLayer { + case decryptedMessageLayer(randomBytes: Buffer, layer: Int32, inSeqNo: Int32, outSeqNo: Int32, message: SecretApi46.DecryptedMessage) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageLayer(let randomBytes, let layer, let inSeqNo, let outSeqNo, let message): + if boxed { + buffer.appendInt32(467867529) + } + serializeBytes(randomBytes, buffer: buffer, boxed: false) + serializeInt32(layer, buffer: buffer, boxed: false) + serializeInt32(inSeqNo, buffer: buffer, boxed: false) + serializeInt32(outSeqNo, buffer: buffer, boxed: false) + message.serialize(buffer, true) + break + } + } + + fileprivate static func parse_decryptedMessageLayer(_ reader: BufferReader) -> DecryptedMessageLayer? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: SecretApi46.DecryptedMessage? + if let signature = reader.readInt32() { + _5 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.DecryptedMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi46.DecryptedMessageLayer.decryptedMessageLayer(randomBytes: _1!, layer: _2!, inSeqNo: _3!, outSeqNo: _4!, message: _5!) + } + else { + return nil + } + } + + } + + public enum DecryptedMessage { + case decryptedMessageService(randomId: Int64, action: SecretApi46.DecryptedMessageAction) + case decryptedMessage(flags: Int32, randomId: Int64, ttl: Int32, message: String, media: SecretApi46.DecryptedMessageMedia?, entities: [SecretApi46.MessageEntity]?, viaBotName: String?, replyToRandomId: Int64?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageService(let randomId, let action): + if boxed { + buffer.appendInt32(1930838368) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + case .decryptedMessage(let flags, let randomId, let ttl, let message, let media, let entities, let viaBotName, let replyToRandomId): + if boxed { + buffer.appendInt32(917541342) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeInt32(ttl, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 11) != 0 {serializeString(viaBotName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt64(replyToRandomId!, buffer: buffer, boxed: false)} + break + } + } + + fileprivate static func parse_decryptedMessageService(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: SecretApi46.DecryptedMessageAction? + if let signature = reader.readInt32() { + _2 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.DecryptedMessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DecryptedMessage.decryptedMessageService(randomId: _1!, action: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessage(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: SecretApi46.DecryptedMessageMedia? + if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() { + _5 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.DecryptedMessageMedia + } } + var _6: [SecretApi46.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _6 = SecretApi46.parseVector(reader, elementSignature: 0, elementType: SecretApi46.MessageEntity.self) + } } + var _7: String? + if Int(_1!) & Int(1 << 11) != 0 {_7 = parseString(reader) } + var _8: Int64? + if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt64() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 9) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 7) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return SecretApi46.DecryptedMessage.decryptedMessage(flags: _1!, randomId: _2!, ttl: _3!, message: _4!, media: _5, entities: _6, viaBotName: _7, replyToRandomId: _8) + } + else { + return nil + } + } + + } + + public enum DocumentAttribute { + case documentAttributeImageSize(w: Int32, h: Int32) + case documentAttributeAnimated + case documentAttributeVideo(duration: Int32, w: Int32, h: Int32) + case documentAttributeFilename(fileName: String) + case documentAttributeSticker(alt: String, stickerset: SecretApi46.InputStickerSet) + case documentAttributeAudio(flags: Int32, duration: Int32, title: String?, performer: String?, waveform: Buffer?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .documentAttributeImageSize(let w, let h): + if boxed { + buffer.appendInt32(1815593308) + } + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .documentAttributeAnimated: + if boxed { + buffer.appendInt32(297109817) + } + + break + case .documentAttributeVideo(let duration, let w, let h): + if boxed { + buffer.appendInt32(1494273227) + } + serializeInt32(duration, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .documentAttributeFilename(let fileName): + if boxed { + buffer.appendInt32(358154344) + } + serializeString(fileName, buffer: buffer, boxed: false) + break + case .documentAttributeSticker(let alt, let stickerset): + if boxed { + buffer.appendInt32(978674434) + } + serializeString(alt, buffer: buffer, boxed: false) + stickerset.serialize(buffer, true) + break + case .documentAttributeAudio(let flags, let duration, let title, let performer, let waveform): + if boxed { + buffer.appendInt32(-1739392570) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(performer!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(waveform!, buffer: buffer, boxed: false)} + break + } + } + + fileprivate static func parse_documentAttributeImageSize(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DocumentAttribute.documentAttributeImageSize(w: _1!, h: _2!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeAnimated(_ reader: BufferReader) -> DocumentAttribute? { + return SecretApi46.DocumentAttribute.documentAttributeAnimated + } + fileprivate static func parse_documentAttributeVideo(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi46.DocumentAttribute.documentAttributeVideo(duration: _1!, w: _2!, h: _3!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeFilename(_ reader: BufferReader) -> DocumentAttribute? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DocumentAttribute.documentAttributeFilename(fileName: _1!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeSticker(_ reader: BufferReader) -> DocumentAttribute? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi46.InputStickerSet? + if let signature = reader.readInt32() { + _2 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.InputStickerSet + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DocumentAttribute.documentAttributeSticker(alt: _1!, stickerset: _2!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeAudio(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi46.DocumentAttribute.documentAttributeAudio(flags: _1!, duration: _2!, title: _3, performer: _4, waveform: _5) + } + else { + return nil + } + } + + } + + public enum InputStickerSet { + case inputStickerSetShortName(shortName: String) + case inputStickerSetEmpty + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputStickerSetShortName(let shortName): + if boxed { + buffer.appendInt32(-2044933984) + } + serializeString(shortName, buffer: buffer, boxed: false) + break + case .inputStickerSetEmpty: + if boxed { + buffer.appendInt32(-4838507) + } + + break + } + } + + fileprivate static func parse_inputStickerSetShortName(_ reader: BufferReader) -> InputStickerSet? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi46.InputStickerSet.inputStickerSetShortName(shortName: _1!) + } + else { + return nil + } + } + fileprivate static func parse_inputStickerSetEmpty(_ reader: BufferReader) -> InputStickerSet? { + return SecretApi46.InputStickerSet.inputStickerSetEmpty + } + + } + + public enum MessageEntity { + case messageEntityUnknown(offset: Int32, length: Int32) + case messageEntityMention(offset: Int32, length: Int32) + case messageEntityHashtag(offset: Int32, length: Int32) + case messageEntityBotCommand(offset: Int32, length: Int32) + case messageEntityUrl(offset: Int32, length: Int32) + case messageEntityEmail(offset: Int32, length: Int32) + case messageEntityBold(offset: Int32, length: Int32) + case messageEntityItalic(offset: Int32, length: Int32) + case messageEntityCode(offset: Int32, length: Int32) + case messageEntityPre(offset: Int32, length: Int32, language: String) + case messageEntityTextUrl(offset: Int32, length: Int32, url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageEntityUnknown(let offset, let length): + if boxed { + buffer.appendInt32(-1148011883) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityMention(let offset, let length): + if boxed { + buffer.appendInt32(-100378723) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityHashtag(let offset, let length): + if boxed { + buffer.appendInt32(1868782349) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBotCommand(let offset, let length): + if boxed { + buffer.appendInt32(1827637959) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityUrl(let offset, let length): + if boxed { + buffer.appendInt32(1859134776) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityEmail(let offset, let length): + if boxed { + buffer.appendInt32(1692693954) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBold(let offset, let length): + if boxed { + buffer.appendInt32(-1117713463) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityItalic(let offset, let length): + if boxed { + buffer.appendInt32(-2106619040) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityCode(let offset, let length): + if boxed { + buffer.appendInt32(681706865) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityPre(let offset, let length, let language): + if boxed { + buffer.appendInt32(1938967520) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(language, buffer: buffer, boxed: false) + break + case .messageEntityTextUrl(let offset, let length, let url): + if boxed { + buffer.appendInt32(1990644519) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_messageEntityUnknown(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityUnknown(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityMention(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityMention(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityHashtag(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityHashtag(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityBotCommand(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityBotCommand(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityUrl(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityEmail(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityEmail(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityBold(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityBold(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityItalic(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityItalic(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityCode(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.MessageEntity.messageEntityCode(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityPre(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi46.MessageEntity.messageEntityPre(offset: _1!, length: _2!, language: _3!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityTextUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi46.MessageEntity.messageEntityTextUrl(offset: _1!, length: _2!, url: _3!) + } + else { + return nil + } + } + + } + + public enum DecryptedMessageMedia { + case decryptedMessageMediaEmpty + case decryptedMessageMediaGeoPoint(lat: Double, long: Double) + case decryptedMessageMediaContact(phoneNumber: String, firstName: String, lastName: String, userId: Int32) + case decryptedMessageMediaAudio(duration: Int32, mimeType: String, size: Int32, key: Buffer, iv: Buffer) + case decryptedMessageMediaExternalDocument(id: Int64, accessHash: Int64, date: Int32, mimeType: String, size: Int32, thumb: SecretApi46.PhotoSize, dcId: Int32, attributes: [SecretApi46.DocumentAttribute]) + case decryptedMessageMediaPhoto(thumb: Buffer, thumbW: Int32, thumbH: Int32, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer, caption: String) + case decryptedMessageMediaDocument(thumb: Buffer, thumbW: Int32, thumbH: Int32, mimeType: String, size: Int32, key: Buffer, iv: Buffer, attributes: [SecretApi46.DocumentAttribute], caption: String) + case decryptedMessageMediaVideo(thumb: Buffer, thumbW: Int32, thumbH: Int32, duration: Int32, mimeType: String, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer, caption: String) + case decryptedMessageMediaVenue(lat: Double, long: Double, title: String, address: String, provider: String, venueId: String) + case decryptedMessageMediaWebPage(url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageMediaEmpty: + if boxed { + buffer.appendInt32(144661578) + } + + break + case .decryptedMessageMediaGeoPoint(let lat, let long): + if boxed { + buffer.appendInt32(893913689) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaContact(let phoneNumber, let firstName, let lastName, let userId): + if boxed { + buffer.appendInt32(1485441687) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaAudio(let duration, let mimeType, let size, let key, let iv): + if boxed { + buffer.appendInt32(1474341323) + } + serializeInt32(duration, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaExternalDocument(let id, let accessHash, let date, let mimeType, let size, let thumb, let dcId, let attributes): + if boxed { + buffer.appendInt32(-90853155) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + thumb.serialize(buffer, true) + serializeInt32(dcId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + case .decryptedMessageMediaPhoto(let thumb, let thumbW, let thumbH, let w, let h, let size, let key, let iv, let caption): + if boxed { + buffer.appendInt32(-235238024) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaDocument(let thumb, let thumbW, let thumbH, let mimeType, let size, let key, let iv, let attributes, let caption): + if boxed { + buffer.appendInt32(2063502050) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaVideo(let thumb, let thumbW, let thumbH, let duration, let mimeType, let w, let h, let size, let key, let iv, let caption): + if boxed { + buffer.appendInt32(-1760785394) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaVenue(let lat, let long, let title, let address, let provider, let venueId): + if boxed { + buffer.appendInt32(-1978796689) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaWebPage(let url): + if boxed { + buffer.appendInt32(-452652584) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_decryptedMessageMediaEmpty(_ reader: BufferReader) -> DecryptedMessageMedia? { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaEmpty + } + fileprivate static func parse_decryptedMessageMediaGeoPoint(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaGeoPoint(lat: _1!, long: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaContact(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, userId: _4!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaAudio(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaAudio(duration: _1!, mimeType: _2!, size: _3!, key: _4!, iv: _5!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaExternalDocument(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: SecretApi46.PhotoSize? + if let signature = reader.readInt32() { + _6 = SecretApi46.parse(reader, signature: signature) as? SecretApi46.PhotoSize + } + var _7: Int32? + _7 = reader.readInt32() + var _8: [SecretApi46.DocumentAttribute]? + if let _ = reader.readInt32() { + _8 = SecretApi46.parseVector(reader, elementSignature: 0, elementType: SecretApi46.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaExternalDocument(id: _1!, accessHash: _2!, date: _3!, mimeType: _4!, size: _5!, thumb: _6!, dcId: _7!, attributes: _8!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaPhoto(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Buffer? + _8 = parseBytes(reader) + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: _1!, thumbW: _2!, thumbH: _3!, w: _4!, h: _5!, size: _6!, key: _7!, iv: _8!, caption: _9!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaDocument(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: Buffer? + _6 = parseBytes(reader) + var _7: Buffer? + _7 = parseBytes(reader) + var _8: [SecretApi46.DocumentAttribute]? + if let _ = reader.readInt32() { + _8 = SecretApi46.parseVector(reader, elementSignature: 0, elementType: SecretApi46.DocumentAttribute.self) + } + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: _1!, thumbW: _2!, thumbH: _3!, mimeType: _4!, size: _5!, key: _6!, iv: _7!, attributes: _8!, caption: _9!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaVideo(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + var _9: Buffer? + _9 = parseBytes(reader) + var _10: Buffer? + _10 = parseBytes(reader) + var _11: String? + _11 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaVideo(thumb: _1!, thumbW: _2!, thumbH: _3!, duration: _4!, mimeType: _5!, w: _6!, h: _7!, size: _8!, key: _9!, iv: _10!, caption: _11!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaVenue(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaVenue(lat: _1!, long: _2!, title: _3!, address: _4!, provider: _5!, venueId: _6!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaWebPage(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi46.DecryptedMessageMedia.decryptedMessageMediaWebPage(url: _1!) + } + else { + return nil + } + } + + } + + public struct functions { + + } + +} diff --git a/submodules/TelegramCore/TelegramCore/SecretApiLayer73.swift b/submodules/TelegramCore/TelegramCore/SecretApiLayer73.swift new file mode 100644 index 0000000000..07a80ed2b5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretApiLayer73.swift @@ -0,0 +1,1513 @@ + +fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { + var dict: [Int32 : (BufferReader) -> Any?] = [:] + dict[-1471112230] = { return $0.readInt32() } + dict[570911930] = { return $0.readInt64() } + dict[571523412] = { return $0.readDouble() } + dict[-1255641564] = { return parseString($0) } + dict[-1586283796] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionSetMessageTTL($0) } + dict[206520510] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionReadMessages($0) } + dict[1700872964] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionDeleteMessages($0) } + dict[-1967000459] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionScreenshotMessages($0) } + dict[1729750108] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionFlushHistory($0) } + dict[-217806717] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionNotifyLayer($0) } + dict[1360072880] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionResend($0) } + dict[-204906213] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionRequestKey($0) } + dict[1877046107] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionAcceptKey($0) } + dict[-586814357] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionAbortKey($0) } + dict[-332526693] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionCommitKey($0) } + dict[-1473258141] = { return SecretApi73.DecryptedMessageAction.parse_decryptedMessageActionNoop($0) } + dict[236446268] = { return SecretApi73.PhotoSize.parse_photoSizeEmpty($0) } + dict[2009052699] = { return SecretApi73.PhotoSize.parse_photoSize($0) } + dict[-374917894] = { return SecretApi73.PhotoSize.parse_photoCachedSize($0) } + dict[2086234950] = { return SecretApi73.FileLocation.parse_fileLocationUnavailable($0) } + dict[1406570614] = { return SecretApi73.FileLocation.parse_fileLocation($0) } + dict[467867529] = { return SecretApi73.DecryptedMessageLayer.parse_decryptedMessageLayer($0) } + dict[1930838368] = { return SecretApi73.DecryptedMessage.parse_decryptedMessageService($0) } + dict[-1848883596] = { return SecretApi73.DecryptedMessage.parse_decryptedMessage($0) } + dict[1815593308] = { return SecretApi73.DocumentAttribute.parse_documentAttributeImageSize($0) } + dict[297109817] = { return SecretApi73.DocumentAttribute.parse_documentAttributeAnimated($0) } + dict[358154344] = { return SecretApi73.DocumentAttribute.parse_documentAttributeFilename($0) } + dict[978674434] = { return SecretApi73.DocumentAttribute.parse_documentAttributeSticker($0) } + dict[-1739392570] = { return SecretApi73.DocumentAttribute.parse_documentAttributeAudio($0) } + dict[250621158] = { return SecretApi73.DocumentAttribute.parse_documentAttributeVideo($0) } + dict[-2044933984] = { return SecretApi73.InputStickerSet.parse_inputStickerSetShortName($0) } + dict[-4838507] = { return SecretApi73.InputStickerSet.parse_inputStickerSetEmpty($0) } + dict[-1148011883] = { return SecretApi73.MessageEntity.parse_messageEntityUnknown($0) } + dict[-100378723] = { return SecretApi73.MessageEntity.parse_messageEntityMention($0) } + dict[1868782349] = { return SecretApi73.MessageEntity.parse_messageEntityHashtag($0) } + dict[1827637959] = { return SecretApi73.MessageEntity.parse_messageEntityBotCommand($0) } + dict[1859134776] = { return SecretApi73.MessageEntity.parse_messageEntityUrl($0) } + dict[1692693954] = { return SecretApi73.MessageEntity.parse_messageEntityEmail($0) } + dict[-1117713463] = { return SecretApi73.MessageEntity.parse_messageEntityBold($0) } + dict[-2106619040] = { return SecretApi73.MessageEntity.parse_messageEntityItalic($0) } + dict[681706865] = { return SecretApi73.MessageEntity.parse_messageEntityCode($0) } + dict[1938967520] = { return SecretApi73.MessageEntity.parse_messageEntityPre($0) } + dict[1990644519] = { return SecretApi73.MessageEntity.parse_messageEntityTextUrl($0) } + dict[144661578] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaEmpty($0) } + dict[893913689] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaGeoPoint($0) } + dict[1485441687] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaContact($0) } + dict[1474341323] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaAudio($0) } + dict[-90853155] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaExternalDocument($0) } + dict[-235238024] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaPhoto($0) } + dict[2063502050] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaDocument($0) } + dict[-1760785394] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaVideo($0) } + dict[-1978796689] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaVenue($0) } + dict[-452652584] = { return SecretApi73.DecryptedMessageMedia.parse_decryptedMessageMediaWebPage($0) } + return dict +}() + +public struct SecretApi73 { + public static func parse(_ buffer: Buffer) -> Any? { + let reader = BufferReader(buffer) + if let signature = reader.readInt32() { + return parse(reader, signature: signature) + } + return nil + } + + fileprivate static func parse(_ reader: BufferReader, signature: Int32) -> Any? { + if let parser = parsers[signature] { + return parser(reader) + } + else { + Logger.shared.log("TL", "Type constructor \(String(signature, radix: 16, uppercase: false)) not found") + return nil + } + } + + fileprivate static func parseVector(_ reader: BufferReader, elementSignature: Int32, elementType: T.Type) -> [T]? { + if let count = reader.readInt32() { + var array = [T]() + var i: Int32 = 0 + while i < count { + var signature = elementSignature + if elementSignature == 0 { + if let unboxedSignature = reader.readInt32() { + signature = unboxedSignature + } + else { + return nil + } + } + if let item = SecretApi73.parse(reader, signature: signature) as? T { + array.append(item) + } + else { + return nil + } + i += 1 + } + return array + } + return nil + } + + public static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) { + switch object { + case let _1 as SecretApi73.DecryptedMessageAction: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.PhotoSize: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.FileLocation: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.DecryptedMessageLayer: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.DecryptedMessage: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.DocumentAttribute: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.InputStickerSet: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.MessageEntity: + _1.serialize(buffer, boxed) + case let _1 as SecretApi73.DecryptedMessageMedia: + _1.serialize(buffer, boxed) + default: + break + } + } + + public enum DecryptedMessageAction { + case decryptedMessageActionSetMessageTTL(ttlSeconds: Int32) + case decryptedMessageActionReadMessages(randomIds: [Int64]) + case decryptedMessageActionDeleteMessages(randomIds: [Int64]) + case decryptedMessageActionScreenshotMessages(randomIds: [Int64]) + case decryptedMessageActionFlushHistory + case decryptedMessageActionNotifyLayer(layer: Int32) + case decryptedMessageActionResend(startSeqNo: Int32, endSeqNo: Int32) + case decryptedMessageActionRequestKey(exchangeId: Int64, gA: Buffer) + case decryptedMessageActionAcceptKey(exchangeId: Int64, gB: Buffer, keyFingerprint: Int64) + case decryptedMessageActionAbortKey(exchangeId: Int64) + case decryptedMessageActionCommitKey(exchangeId: Int64, keyFingerprint: Int64) + case decryptedMessageActionNoop + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageActionSetMessageTTL(let ttlSeconds): + if boxed { + buffer.appendInt32(-1586283796) + } + serializeInt32(ttlSeconds, buffer: buffer, boxed: false) + break + case .decryptedMessageActionReadMessages(let randomIds): + if boxed { + buffer.appendInt32(206520510) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionDeleteMessages(let randomIds): + if boxed { + buffer.appendInt32(1700872964) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionScreenshotMessages(let randomIds): + if boxed { + buffer.appendInt32(-1967000459) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionFlushHistory: + if boxed { + buffer.appendInt32(1729750108) + } + + break + case .decryptedMessageActionNotifyLayer(let layer): + if boxed { + buffer.appendInt32(-217806717) + } + serializeInt32(layer, buffer: buffer, boxed: false) + break + case .decryptedMessageActionResend(let startSeqNo, let endSeqNo): + if boxed { + buffer.appendInt32(1360072880) + } + serializeInt32(startSeqNo, buffer: buffer, boxed: false) + serializeInt32(endSeqNo, buffer: buffer, boxed: false) + break + case .decryptedMessageActionRequestKey(let exchangeId, let gA): + if boxed { + buffer.appendInt32(-204906213) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeBytes(gA, buffer: buffer, boxed: false) + break + case .decryptedMessageActionAcceptKey(let exchangeId, let gB, let keyFingerprint): + if boxed { + buffer.appendInt32(1877046107) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeBytes(gB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .decryptedMessageActionAbortKey(let exchangeId): + if boxed { + buffer.appendInt32(-586814357) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + break + case .decryptedMessageActionCommitKey(let exchangeId, let keyFingerprint): + if boxed { + buffer.appendInt32(-332526693) + } + serializeInt64(exchangeId, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .decryptedMessageActionNoop: + if boxed { + buffer.appendInt32(-1473258141) + } + + break + } + } + fileprivate static func parse_decryptedMessageActionSetMessageTTL(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionSetMessageTTL(ttlSeconds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionReadMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi73.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionReadMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionDeleteMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi73.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionDeleteMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionScreenshotMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi73.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionScreenshotMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionFlushHistory(_ reader: BufferReader) -> DecryptedMessageAction? { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionFlushHistory + } + fileprivate static func parse_decryptedMessageActionNotifyLayer(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionNotifyLayer(layer: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionResend(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionResend(startSeqNo: _1!, endSeqNo: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionRequestKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionRequestKey(exchangeId: _1!, gA: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionAcceptKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionAcceptKey(exchangeId: _1!, gB: _2!, keyFingerprint: _3!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionAbortKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionAbortKey(exchangeId: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionCommitKey(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionCommitKey(exchangeId: _1!, keyFingerprint: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionNoop(_ reader: BufferReader) -> DecryptedMessageAction? { + return SecretApi73.DecryptedMessageAction.decryptedMessageActionNoop + } + + + } + + public enum PhotoSize { + case photoSizeEmpty(type: String) + case photoSize(type: String, location: SecretApi73.FileLocation, w: Int32, h: Int32, size: Int32) + case photoCachedSize(type: String, location: SecretApi73.FileLocation, w: Int32, h: Int32, bytes: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .photoSizeEmpty(let type): + if boxed { + buffer.appendInt32(236446268) + } + serializeString(type, buffer: buffer, boxed: false) + break + case .photoSize(let type, let location, let w, let h, let size): + if boxed { + buffer.appendInt32(2009052699) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + break + case .photoCachedSize(let type, let location, let w, let h, let bytes): + if boxed { + buffer.appendInt32(-374917894) + } + serializeString(type, buffer: buffer, boxed: false) + location.serialize(buffer, true) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_photoSizeEmpty(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi73.PhotoSize.photoSizeEmpty(type: _1!) + } + else { + return nil + } + } + fileprivate static func parse_photoSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi73.FileLocation? + if let signature = reader.readInt32() { + _2 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi73.PhotoSize.photoSize(type: _1!, location: _2!, w: _3!, h: _4!, size: _5!) + } + else { + return nil + } + } + fileprivate static func parse_photoCachedSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi73.FileLocation? + if let signature = reader.readInt32() { + _2 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.FileLocation + } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi73.PhotoSize.photoCachedSize(type: _1!, location: _2!, w: _3!, h: _4!, bytes: _5!) + } + else { + return nil + } + } + + + } + + public enum FileLocation { + case fileLocationUnavailable(volumeId: Int64, localId: Int32, secret: Int64) + case fileLocation(dcId: Int32, volumeId: Int64, localId: Int32, secret: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileLocationUnavailable(let volumeId, let localId, let secret): + if boxed { + buffer.appendInt32(2086234950) + } + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + serializeInt64(secret, buffer: buffer, boxed: false) + break + case .fileLocation(let dcId, let volumeId, let localId, let secret): + if boxed { + buffer.appendInt32(1406570614) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt64(volumeId, buffer: buffer, boxed: false) + serializeInt32(localId, buffer: buffer, boxed: false) + serializeInt64(secret, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_fileLocationUnavailable(_ reader: BufferReader) -> FileLocation? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi73.FileLocation.fileLocationUnavailable(volumeId: _1!, localId: _2!, secret: _3!) + } + else { + return nil + } + } + fileprivate static func parse_fileLocation(_ reader: BufferReader) -> FileLocation? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int64? + _4 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi73.FileLocation.fileLocation(dcId: _1!, volumeId: _2!, localId: _3!, secret: _4!) + } + else { + return nil + } + } + + + } + + public enum DecryptedMessageLayer { + case decryptedMessageLayer(randomBytes: Buffer, layer: Int32, inSeqNo: Int32, outSeqNo: Int32, message: SecretApi73.DecryptedMessage) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageLayer(let randomBytes, let layer, let inSeqNo, let outSeqNo, let message): + if boxed { + buffer.appendInt32(467867529) + } + serializeBytes(randomBytes, buffer: buffer, boxed: false) + serializeInt32(layer, buffer: buffer, boxed: false) + serializeInt32(inSeqNo, buffer: buffer, boxed: false) + serializeInt32(outSeqNo, buffer: buffer, boxed: false) + message.serialize(buffer, true) + break + } + } + fileprivate static func parse_decryptedMessageLayer(_ reader: BufferReader) -> DecryptedMessageLayer? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: SecretApi73.DecryptedMessage? + if let signature = reader.readInt32() { + _5 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.DecryptedMessage + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi73.DecryptedMessageLayer.decryptedMessageLayer(randomBytes: _1!, layer: _2!, inSeqNo: _3!, outSeqNo: _4!, message: _5!) + } + else { + return nil + } + } + + + } + + public enum DecryptedMessage { + case decryptedMessageService(randomId: Int64, action: SecretApi73.DecryptedMessageAction) + case decryptedMessage(flags: Int32, randomId: Int64, ttl: Int32, message: String, media: SecretApi73.DecryptedMessageMedia?, entities: [SecretApi73.MessageEntity]?, viaBotName: String?, replyToRandomId: Int64?, groupedId: Int64?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageService(let randomId, let action): + if boxed { + buffer.appendInt32(1930838368) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + case .decryptedMessage(let flags, let randomId, let ttl, let message, let media, let entities, let viaBotName, let replyToRandomId, let groupedId): + if boxed { + buffer.appendInt32(-1848883596) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeInt32(ttl, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)} + if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 11) != 0 {serializeString(viaBotName!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeInt64(replyToRandomId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 17) != 0 {serializeInt64(groupedId!, buffer: buffer, boxed: false)} + break + } + } + fileprivate static func parse_decryptedMessageService(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: SecretApi73.DecryptedMessageAction? + if let signature = reader.readInt32() { + _2 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.DecryptedMessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DecryptedMessage.decryptedMessageService(randomId: _1!, action: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessage(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: SecretApi73.DecryptedMessageMedia? + if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() { + _5 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.DecryptedMessageMedia + } } + var _6: [SecretApi73.MessageEntity]? + if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() { + _6 = SecretApi73.parseVector(reader, elementSignature: 0, elementType: SecretApi73.MessageEntity.self) + } } + var _7: String? + if Int(_1!) & Int(1 << 11) != 0 {_7 = parseString(reader) } + var _8: Int64? + if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt64() } + var _9: Int64? + if Int(_1!) & Int(1 << 17) != 0 {_9 = reader.readInt64() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 9) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 7) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 17) == 0) || _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi73.DecryptedMessage.decryptedMessage(flags: _1!, randomId: _2!, ttl: _3!, message: _4!, media: _5, entities: _6, viaBotName: _7, replyToRandomId: _8, groupedId: _9) + } + else { + return nil + } + } + + + } + + public enum DocumentAttribute { + case documentAttributeImageSize(w: Int32, h: Int32) + case documentAttributeAnimated + case documentAttributeFilename(fileName: String) + case documentAttributeSticker(alt: String, stickerset: SecretApi73.InputStickerSet) + case documentAttributeAudio(flags: Int32, duration: Int32, title: String?, performer: String?, waveform: Buffer?) + case documentAttributeVideo(flags: Int32, duration: Int32, w: Int32, h: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .documentAttributeImageSize(let w, let h): + if boxed { + buffer.appendInt32(1815593308) + } + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + case .documentAttributeAnimated: + if boxed { + buffer.appendInt32(297109817) + } + + break + case .documentAttributeFilename(let fileName): + if boxed { + buffer.appendInt32(358154344) + } + serializeString(fileName, buffer: buffer, boxed: false) + break + case .documentAttributeSticker(let alt, let stickerset): + if boxed { + buffer.appendInt32(978674434) + } + serializeString(alt, buffer: buffer, boxed: false) + stickerset.serialize(buffer, true) + break + case .documentAttributeAudio(let flags, let duration, let title, let performer, let waveform): + if boxed { + buffer.appendInt32(-1739392570) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(performer!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(waveform!, buffer: buffer, boxed: false)} + break + case .documentAttributeVideo(let flags, let duration, let w, let h): + if boxed { + buffer.appendInt32(250621158) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_documentAttributeImageSize(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DocumentAttribute.documentAttributeImageSize(w: _1!, h: _2!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeAnimated(_ reader: BufferReader) -> DocumentAttribute? { + return SecretApi73.DocumentAttribute.documentAttributeAnimated + } + fileprivate static func parse_documentAttributeFilename(_ reader: BufferReader) -> DocumentAttribute? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DocumentAttribute.documentAttributeFilename(fileName: _1!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeSticker(_ reader: BufferReader) -> DocumentAttribute? { + var _1: String? + _1 = parseString(reader) + var _2: SecretApi73.InputStickerSet? + if let signature = reader.readInt32() { + _2 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.InputStickerSet + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DocumentAttribute.documentAttributeSticker(alt: _1!, stickerset: _2!) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeAudio(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_5 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi73.DocumentAttribute.documentAttributeAudio(flags: _1!, duration: _2!, title: _3, performer: _4, waveform: _5) + } + else { + return nil + } + } + fileprivate static func parse_documentAttributeVideo(_ reader: BufferReader) -> DocumentAttribute? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi73.DocumentAttribute.documentAttributeVideo(flags: _1!, duration: _2!, w: _3!, h: _4!) + } + else { + return nil + } + } + + + } + + public enum InputStickerSet { + case inputStickerSetShortName(shortName: String) + case inputStickerSetEmpty + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputStickerSetShortName(let shortName): + if boxed { + buffer.appendInt32(-2044933984) + } + serializeString(shortName, buffer: buffer, boxed: false) + break + case .inputStickerSetEmpty: + if boxed { + buffer.appendInt32(-4838507) + } + + break + } + } + fileprivate static func parse_inputStickerSetShortName(_ reader: BufferReader) -> InputStickerSet? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi73.InputStickerSet.inputStickerSetShortName(shortName: _1!) + } + else { + return nil + } + } + fileprivate static func parse_inputStickerSetEmpty(_ reader: BufferReader) -> InputStickerSet? { + return SecretApi73.InputStickerSet.inputStickerSetEmpty + } + + + } + + public enum MessageEntity { + case messageEntityUnknown(offset: Int32, length: Int32) + case messageEntityMention(offset: Int32, length: Int32) + case messageEntityHashtag(offset: Int32, length: Int32) + case messageEntityBotCommand(offset: Int32, length: Int32) + case messageEntityUrl(offset: Int32, length: Int32) + case messageEntityEmail(offset: Int32, length: Int32) + case messageEntityBold(offset: Int32, length: Int32) + case messageEntityItalic(offset: Int32, length: Int32) + case messageEntityCode(offset: Int32, length: Int32) + case messageEntityPre(offset: Int32, length: Int32, language: String) + case messageEntityTextUrl(offset: Int32, length: Int32, url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageEntityUnknown(let offset, let length): + if boxed { + buffer.appendInt32(-1148011883) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityMention(let offset, let length): + if boxed { + buffer.appendInt32(-100378723) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityHashtag(let offset, let length): + if boxed { + buffer.appendInt32(1868782349) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBotCommand(let offset, let length): + if boxed { + buffer.appendInt32(1827637959) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityUrl(let offset, let length): + if boxed { + buffer.appendInt32(1859134776) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityEmail(let offset, let length): + if boxed { + buffer.appendInt32(1692693954) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityBold(let offset, let length): + if boxed { + buffer.appendInt32(-1117713463) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityItalic(let offset, let length): + if boxed { + buffer.appendInt32(-2106619040) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityCode(let offset, let length): + if boxed { + buffer.appendInt32(681706865) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break + case .messageEntityPre(let offset, let length, let language): + if boxed { + buffer.appendInt32(1938967520) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(language, buffer: buffer, boxed: false) + break + case .messageEntityTextUrl(let offset, let length, let url): + if boxed { + buffer.appendInt32(1990644519) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_messageEntityUnknown(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityUnknown(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityMention(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityMention(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityHashtag(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityHashtag(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityBotCommand(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityBotCommand(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityUrl(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityEmail(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityEmail(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityBold(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityBold(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityItalic(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityItalic(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityCode(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.MessageEntity.messageEntityCode(offset: _1!, length: _2!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityPre(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi73.MessageEntity.messageEntityPre(offset: _1!, length: _2!, language: _3!) + } + else { + return nil + } + } + fileprivate static func parse_messageEntityTextUrl(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi73.MessageEntity.messageEntityTextUrl(offset: _1!, length: _2!, url: _3!) + } + else { + return nil + } + } + + + } + + public enum DecryptedMessageMedia { + case decryptedMessageMediaEmpty + case decryptedMessageMediaGeoPoint(lat: Double, long: Double) + case decryptedMessageMediaContact(phoneNumber: String, firstName: String, lastName: String, userId: Int32) + case decryptedMessageMediaAudio(duration: Int32, mimeType: String, size: Int32, key: Buffer, iv: Buffer) + case decryptedMessageMediaExternalDocument(id: Int64, accessHash: Int64, date: Int32, mimeType: String, size: Int32, thumb: SecretApi73.PhotoSize, dcId: Int32, attributes: [SecretApi73.DocumentAttribute]) + case decryptedMessageMediaPhoto(thumb: Buffer, thumbW: Int32, thumbH: Int32, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer, caption: String) + case decryptedMessageMediaDocument(thumb: Buffer, thumbW: Int32, thumbH: Int32, mimeType: String, size: Int32, key: Buffer, iv: Buffer, attributes: [SecretApi73.DocumentAttribute], caption: String) + case decryptedMessageMediaVideo(thumb: Buffer, thumbW: Int32, thumbH: Int32, duration: Int32, mimeType: String, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer, caption: String) + case decryptedMessageMediaVenue(lat: Double, long: Double, title: String, address: String, provider: String, venueId: String) + case decryptedMessageMediaWebPage(url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageMediaEmpty: + if boxed { + buffer.appendInt32(144661578) + } + + break + case .decryptedMessageMediaGeoPoint(let lat, let long): + if boxed { + buffer.appendInt32(893913689) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaContact(let phoneNumber, let firstName, let lastName, let userId): + if boxed { + buffer.appendInt32(1485441687) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaAudio(let duration, let mimeType, let size, let key, let iv): + if boxed { + buffer.appendInt32(1474341323) + } + serializeInt32(duration, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaExternalDocument(let id, let accessHash, let date, let mimeType, let size, let thumb, let dcId, let attributes): + if boxed { + buffer.appendInt32(-90853155) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + thumb.serialize(buffer, true) + serializeInt32(dcId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + case .decryptedMessageMediaPhoto(let thumb, let thumbW, let thumbH, let w, let h, let size, let key, let iv, let caption): + if boxed { + buffer.appendInt32(-235238024) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaDocument(let thumb, let thumbW, let thumbH, let mimeType, let size, let key, let iv, let attributes, let caption): + if boxed { + buffer.appendInt32(2063502050) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaVideo(let thumb, let thumbW, let thumbH, let duration, let mimeType, let w, let h, let size, let key, let iv, let caption): + if boxed { + buffer.appendInt32(-1760785394) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + serializeString(caption, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaVenue(let lat, let long, let title, let address, let provider, let venueId): + if boxed { + buffer.appendInt32(-1978796689) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(address, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + serializeString(venueId, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaWebPage(let url): + if boxed { + buffer.appendInt32(-452652584) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_decryptedMessageMediaEmpty(_ reader: BufferReader) -> DecryptedMessageMedia? { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaEmpty + } + fileprivate static func parse_decryptedMessageMediaGeoPoint(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaGeoPoint(lat: _1!, long: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaContact(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, userId: _4!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaAudio(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Buffer? + _5 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaAudio(duration: _1!, mimeType: _2!, size: _3!, key: _4!, iv: _5!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaExternalDocument(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: SecretApi73.PhotoSize? + if let signature = reader.readInt32() { + _6 = SecretApi73.parse(reader, signature: signature) as? SecretApi73.PhotoSize + } + var _7: Int32? + _7 = reader.readInt32() + var _8: [SecretApi73.DocumentAttribute]? + if let _ = reader.readInt32() { + _8 = SecretApi73.parseVector(reader, elementSignature: 0, elementType: SecretApi73.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaExternalDocument(id: _1!, accessHash: _2!, date: _3!, mimeType: _4!, size: _5!, thumb: _6!, dcId: _7!, attributes: _8!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaPhoto(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Buffer? + _8 = parseBytes(reader) + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: _1!, thumbW: _2!, thumbH: _3!, w: _4!, h: _5!, size: _6!, key: _7!, iv: _8!, caption: _9!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaDocument(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: Buffer? + _6 = parseBytes(reader) + var _7: Buffer? + _7 = parseBytes(reader) + var _8: [SecretApi73.DocumentAttribute]? + if let _ = reader.readInt32() { + _8 = SecretApi73.parseVector(reader, elementSignature: 0, elementType: SecretApi73.DocumentAttribute.self) + } + var _9: String? + _9 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: _1!, thumbW: _2!, thumbH: _3!, mimeType: _4!, size: _5!, key: _6!, iv: _7!, attributes: _8!, caption: _9!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaVideo(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Int32? + _8 = reader.readInt32() + var _9: Buffer? + _9 = parseBytes(reader) + var _10: Buffer? + _10 = parseBytes(reader) + var _11: String? + _11 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaVideo(thumb: _1!, thumbW: _2!, thumbH: _3!, duration: _4!, mimeType: _5!, w: _6!, h: _7!, size: _8!, key: _9!, iv: _10!, caption: _11!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaVenue(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: String? + _6 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaVenue(lat: _1!, long: _2!, title: _3!, address: _4!, provider: _5!, venueId: _6!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaWebPage(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return SecretApi73.DecryptedMessageMedia.decryptedMessageMediaWebPage(url: _1!) + } + else { + return nil + } + } + + + } + + public struct functions { + + } + +} diff --git a/submodules/TelegramCore/TelegramCore/SecretApiLayer8.swift b/submodules/TelegramCore/TelegramCore/SecretApiLayer8.swift new file mode 100644 index 0000000000..a3ef3bf64c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretApiLayer8.swift @@ -0,0 +1,532 @@ + + +fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { + var dict: [Int32 : (BufferReader) -> Any?] = [:] + dict[-1471112230] = { return $0.readInt32() } + dict[570911930] = { return $0.readInt64() } + dict[571523412] = { return $0.readDouble() } + dict[-1255641564] = { return parseString($0) } + dict[528568095] = { return SecretApi8.DecryptedMessage.parse_decryptedMessage($0) } + dict[-1438109059] = { return SecretApi8.DecryptedMessage.parse_decryptedMessageService($0) } + dict[144661578] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaEmpty($0) } + dict[846826124] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaPhoto($0) } + dict[1290694387] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaVideo($0) } + dict[893913689] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaGeoPoint($0) } + dict[1485441687] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaContact($0) } + dict[-1332395189] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaDocument($0) } + dict[1619031439] = { return SecretApi8.DecryptedMessageMedia.parse_decryptedMessageMediaAudio($0) } + dict[-1586283796] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionSetMessageTTL($0) } + dict[206520510] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionReadMessages($0) } + dict[1700872964] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionDeleteMessages($0) } + dict[-1967000459] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionScreenshotMessages($0) } + dict[1729750108] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionFlushHistory($0) } + dict[-217806717] = { return SecretApi8.DecryptedMessageAction.parse_decryptedMessageActionNotifyLayer($0) } + return dict +}() + +public struct SecretApi8 { + public static func parse(_ buffer: Buffer) -> Any? { + let reader = BufferReader(buffer) + if let signature = reader.readInt32() { + return parse(reader, signature: signature) + } + return nil + } + + fileprivate static func parse(_ reader: BufferReader, signature: Int32) -> Any? { + if let parser = parsers[signature] { + return parser(reader) + } + else { + Logger.shared.log("TL", "Type constructor \(String(signature, radix: 16, uppercase: false)) not found") + return nil + } + } + + fileprivate static func parseVector(_ reader: BufferReader, elementSignature: Int32, elementType: T.Type) -> [T]? { + if let count = reader.readInt32() { + var array = [T]() + var i: Int32 = 0 + while i < count { + var signature = elementSignature + if elementSignature == 0 { + if let unboxedSignature = reader.readInt32() { + signature = unboxedSignature + } + else { + return nil + } + } + if let item = SecretApi8.parse(reader, signature: signature) as? T { + array.append(item) + } + else { + return nil + } + i += 1 + } + return array + } + return nil + } + + public static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) { + switch object { + case let _1 as SecretApi8.DecryptedMessage: + _1.serialize(buffer, boxed) + case let _1 as SecretApi8.DecryptedMessageMedia: + _1.serialize(buffer, boxed) + case let _1 as SecretApi8.DecryptedMessageAction: + _1.serialize(buffer, boxed) + default: + break + } + } + + public enum DecryptedMessage { + case decryptedMessage(randomId: Int64, randomBytes: Buffer, message: String, media: SecretApi8.DecryptedMessageMedia) + case decryptedMessageService(randomId: Int64, randomBytes: Buffer, action: SecretApi8.DecryptedMessageAction) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessage(let randomId, let randomBytes, let message, let media): + if boxed { + buffer.appendInt32(528568095) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeBytes(randomBytes, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + media.serialize(buffer, true) + break + case .decryptedMessageService(let randomId, let randomBytes, let action): + if boxed { + buffer.appendInt32(-1438109059) + } + serializeInt64(randomId, buffer: buffer, boxed: false) + serializeBytes(randomBytes, buffer: buffer, boxed: false) + action.serialize(buffer, true) + break + } + } + + fileprivate static func parse_decryptedMessage(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + var _4: SecretApi8.DecryptedMessageMedia? + if let signature = reader.readInt32() { + _4 = SecretApi8.parse(reader, signature: signature) as? SecretApi8.DecryptedMessageMedia + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi8.DecryptedMessage.decryptedMessage(randomId: _1!, randomBytes: _2!, message: _3!, media: _4!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageService(_ reader: BufferReader) -> DecryptedMessage? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: SecretApi8.DecryptedMessageAction? + if let signature = reader.readInt32() { + _3 = SecretApi8.parse(reader, signature: signature) as? SecretApi8.DecryptedMessageAction + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return SecretApi8.DecryptedMessage.decryptedMessageService(randomId: _1!, randomBytes: _2!, action: _3!) + } + else { + return nil + } + } + + } + + public enum DecryptedMessageMedia { + case decryptedMessageMediaEmpty + case decryptedMessageMediaPhoto(thumb: Buffer, thumbW: Int32, thumbH: Int32, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer) + case decryptedMessageMediaVideo(thumb: Buffer, thumbW: Int32, thumbH: Int32, duration: Int32, w: Int32, h: Int32, size: Int32, key: Buffer, iv: Buffer) + case decryptedMessageMediaGeoPoint(lat: Double, long: Double) + case decryptedMessageMediaContact(phoneNumber: String, firstName: String, lastName: String, userId: Int32) + case decryptedMessageMediaDocument(thumb: Buffer, thumbW: Int32, thumbH: Int32, fileName: String, mimeType: String, size: Int32, key: Buffer, iv: Buffer) + case decryptedMessageMediaAudio(duration: Int32, size: Int32, key: Buffer, iv: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageMediaEmpty: + if boxed { + buffer.appendInt32(144661578) + } + + break + case .decryptedMessageMediaPhoto(let thumb, let thumbW, let thumbH, let w, let h, let size, let key, let iv): + if boxed { + buffer.appendInt32(846826124) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaVideo(let thumb, let thumbW, let thumbH, let duration, let w, let h, let size, let key, let iv): + if boxed { + buffer.appendInt32(1290694387) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeInt32(duration, buffer: buffer, boxed: false) + serializeInt32(w, buffer: buffer, boxed: false) + serializeInt32(h, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaGeoPoint(let lat, let long): + if boxed { + buffer.appendInt32(893913689) + } + serializeDouble(lat, buffer: buffer, boxed: false) + serializeDouble(long, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaContact(let phoneNumber, let firstName, let lastName, let userId): + if boxed { + buffer.appendInt32(1485441687) + } + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(firstName, buffer: buffer, boxed: false) + serializeString(lastName, buffer: buffer, boxed: false) + serializeInt32(userId, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaDocument(let thumb, let thumbW, let thumbH, let fileName, let mimeType, let size, let key, let iv): + if boxed { + buffer.appendInt32(-1332395189) + } + serializeBytes(thumb, buffer: buffer, boxed: false) + serializeInt32(thumbW, buffer: buffer, boxed: false) + serializeInt32(thumbH, buffer: buffer, boxed: false) + serializeString(fileName, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + case .decryptedMessageMediaAudio(let duration, let size, let key, let iv): + if boxed { + buffer.appendInt32(1619031439) + } + serializeInt32(duration, buffer: buffer, boxed: false) + serializeInt32(size, buffer: buffer, boxed: false) + serializeBytes(key, buffer: buffer, boxed: false) + serializeBytes(iv, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_decryptedMessageMediaEmpty(_ reader: BufferReader) -> DecryptedMessageMedia? { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaEmpty + } + fileprivate static func parse_decryptedMessageMediaPhoto(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Buffer? + _8 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaPhoto(thumb: _1!, thumbW: _2!, thumbH: _3!, w: _4!, h: _5!, size: _6!, key: _7!, iv: _8!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaVideo(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: Int32? + _7 = reader.readInt32() + var _8: Buffer? + _8 = parseBytes(reader) + var _9: Buffer? + _9 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaVideo(thumb: _1!, thumbW: _2!, thumbH: _3!, duration: _4!, w: _5!, h: _6!, size: _7!, key: _8!, iv: _9!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaGeoPoint(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaGeoPoint(lat: _1!, long: _2!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaContact(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, userId: _4!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaDocument(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: Buffer? + _7 = parseBytes(reader) + var _8: Buffer? + _8 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaDocument(thumb: _1!, thumbW: _2!, thumbH: _3!, fileName: _4!, mimeType: _5!, size: _6!, key: _7!, iv: _8!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageMediaAudio(_ reader: BufferReader) -> DecryptedMessageMedia? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return SecretApi8.DecryptedMessageMedia.decryptedMessageMediaAudio(duration: _1!, size: _2!, key: _3!, iv: _4!) + } + else { + return nil + } + } + + } + + public enum DecryptedMessageAction { + case decryptedMessageActionSetMessageTTL(ttlSeconds: Int32) + case decryptedMessageActionReadMessages(randomIds: [Int64]) + case decryptedMessageActionDeleteMessages(randomIds: [Int64]) + case decryptedMessageActionScreenshotMessages(randomIds: [Int64]) + case decryptedMessageActionFlushHistory + case decryptedMessageActionNotifyLayer(layer: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .decryptedMessageActionSetMessageTTL(let ttlSeconds): + if boxed { + buffer.appendInt32(-1586283796) + } + serializeInt32(ttlSeconds, buffer: buffer, boxed: false) + break + case .decryptedMessageActionReadMessages(let randomIds): + if boxed { + buffer.appendInt32(206520510) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionDeleteMessages(let randomIds): + if boxed { + buffer.appendInt32(1700872964) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionScreenshotMessages(let randomIds): + if boxed { + buffer.appendInt32(-1967000459) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(randomIds.count)) + for item in randomIds { + serializeInt64(item, buffer: buffer, boxed: false) + } + break + case .decryptedMessageActionFlushHistory: + if boxed { + buffer.appendInt32(1729750108) + } + + break + case .decryptedMessageActionNotifyLayer(let layer): + if boxed { + buffer.appendInt32(-217806717) + } + serializeInt32(layer, buffer: buffer, boxed: false) + break + } + } + + fileprivate static func parse_decryptedMessageActionSetMessageTTL(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionSetMessageTTL(ttlSeconds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionReadMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi8.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionReadMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionDeleteMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi8.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionDeleteMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionScreenshotMessages(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = SecretApi8.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + let _c1 = _1 != nil + if _c1 { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionScreenshotMessages(randomIds: _1!) + } + else { + return nil + } + } + fileprivate static func parse_decryptedMessageActionFlushHistory(_ reader: BufferReader) -> DecryptedMessageAction? { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionFlushHistory + } + fileprivate static func parse_decryptedMessageActionNotifyLayer(_ reader: BufferReader) -> DecryptedMessageAction? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return SecretApi8.DecryptedMessageAction.decryptedMessageActionNotifyLayer(layer: _1!) + } + else { + return nil + } + } + + } + + public struct functions { + + } + +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatEncryption.swift b/submodules/TelegramCore/TelegramCore/SecretChatEncryption.swift new file mode 100644 index 0000000000..5bce7d278c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatEncryption.swift @@ -0,0 +1,330 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: SecretChatEncryptionMode) -> (aesKey: Data, aesIv: Data) { + switch mode { + case .v1: + let x: Int = 0 + + var sha1AData = Data() + sha1AData.count = 16 + 32 + sha1AData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + memcpy(bytes, msgKey, 16) + memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: x), 32) + } + let sha1A = MTSha1(sha1AData)! + + var sha1BData = Data() + sha1BData.count = 16 + 16 + 16 + sha1BData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + memcpy(bytes, key.key.memory.advanced(by: 32 + x), 16) + memcpy(bytes.advanced(by: 16), msgKey, 16) + memcpy(bytes.advanced(by: 16 + 16), key.key.memory.advanced(by: 48 + x), 16) + } + let sha1B = MTSha1(sha1BData)! + + var sha1CData = Data() + sha1CData.count = 32 + 16 + sha1CData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + memcpy(bytes, key.key.memory.advanced(by: 64 + x), 32) + memcpy(bytes.advanced(by: 32), msgKey, 16) + } + let sha1C = MTSha1(sha1CData)! + + var sha1DData = Data() + sha1DData.count = 16 + 32 + sha1DData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + memcpy(bytes, msgKey, 16) + memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: 96 + x), 32) + } + let sha1D = MTSha1(sha1DData)! + + var aesKey = Data() + aesKey.count = 8 + 12 + 12 + aesKey.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1A.withUnsafeBytes { (sha1A: UnsafePointer) -> Void in + memcpy(bytes, sha1A, 8) + } + sha1B.withUnsafeBytes { (sha1B: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: 8), sha1B.advanced(by: 8), 12) + } + sha1C.withUnsafeBytes { (sha1C: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: 8 + 12), sha1C.advanced(by: 4), 12) + } + } + + var aesIv = Data() + aesIv.count = 12 + 8 + 4 + 8 + aesIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1A.withUnsafeBytes { (sha1A: UnsafePointer) -> Void in + memcpy(bytes, sha1A.advanced(by: 8), 12) + } + sha1B.withUnsafeBytes { (sha1B: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: 12), sha1B, 8) + } + sha1C.withUnsafeBytes { (sha1C: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: 12 + 8), sha1C.advanced(by: 16), 4) + } + sha1D.withUnsafeBytes { (sha1D: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: 12 + 8 + 4), sha1D, 8) + } + } + return (aesKey, aesIv) + case let .v2(role): + var xValue: Int + switch role { + case .creator: + xValue = 0 + case .participant: + xValue = 8 + } + + var sha256_a_data = Data() + sha256_a_data.append(msgKey.assumingMemoryBound(to: UInt8.self), count: 16) + sha256_a_data.append(key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: xValue), count: 36) + + let sha256_a = MTSha256(sha256_a_data)! + + var sha256_b_data = Data() + sha256_b_data.append(key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 40 + xValue), count: 36) + sha256_b_data.append(msgKey.assumingMemoryBound(to: UInt8.self), count: 16) + + let sha256_b = MTSha256(sha256_b_data)! + + var aesKey = Data() + aesKey.append(sha256_a.subdata(in: 0 ..< (0 + 8))) + aesKey.append(sha256_b.subdata(in: 8 ..< (8 + 16))) + aesKey.append(sha256_a.subdata(in: 24 ..< (24 + 8))) + + var aesIv = Data() + aesIv.append(sha256_b.subdata(in: 0 ..< (0 + 8))) + aesIv.append(sha256_a.subdata(in: 8 ..< (8 + 16))) + aesIv.append(sha256_b.subdata(in: 24 ..< (24 + 8))) + + return (aesKey, aesIv) + } +} + +func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, data: MemoryBuffer) -> MemoryBuffer? { + assert(parameters.key.key.length == 256) + + if data.length < 4 + 16 + 16 { + return nil + } + + let msgKey = data.memory.advanced(by: 8) + + switch parameters.mode { + case .v1: + let (aesKey, aesIv) = messageKey(key: parameters.key, msgKey: msgKey, mode: parameters.mode) + + let decryptedData = MTAesDecrypt(Data(bytes: data.memory.advanced(by: 8 + 16), count: data.length - (8 + 16)), aesKey, aesIv)! + + if decryptedData.count < 4 * 3 { + return nil + } + + var payloadLength: Int32 = 0 + decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&payloadLength, bytes, 4) + } + + let paddingLength = decryptedData.count - (Int(payloadLength) + 4) + if Int(payloadLength) > decryptedData.count - 4 || paddingLength > 16 { + return nil + } + + let calculatedMsgKeyData = MTSubdataSha1(decryptedData, 0, UInt(payloadLength) + 4)! + let msgKeyMatches = calculatedMsgKeyData.withUnsafeBytes { (bytes: UnsafePointer) -> Bool in + return memcmp(bytes.advanced(by: calculatedMsgKeyData.count - 16), msgKey, 16) == 0 + } + + if !msgKeyMatches { + return nil + } + + let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Data in + return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength)) + } + return MemoryBuffer(data: result) + case let .v2(role): + let senderRole: SecretChatRole + switch role { + case .creator: + senderRole = .participant + case .participant: + senderRole = .creator + } + let (aesKey, aesIv) = messageKey(key: parameters.key, msgKey: msgKey, mode: .v2(role: senderRole)) + + let decryptedData = MTAesDecrypt(Data(bytes: data.memory.advanced(by: 8 + 16), count: data.length - (8 + 16)), aesKey, aesIv)! + + if decryptedData.count < 4 * 3 { + return nil + } + + var payloadLength: Int32 = 0 + decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&payloadLength, bytes, 4) + } + + let paddingLength = decryptedData.count - (Int(payloadLength) + 4) + + let xValue: Int + switch role { + case .creator: + xValue = 8 + case .participant: + xValue = 0 + } + + var keyLargeData = Data() + keyLargeData.append(parameters.key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 88 + xValue), count: 32) + keyLargeData.append(decryptedData) + + let keyLarge = MTSha256(keyLargeData)! + let localMessageKey = keyLarge.subdata(in: 8 ..< (8 + 16)) + + let msgKeyData = Data(bytes: msgKey.assumingMemoryBound(to: UInt8.self), count: 16) + + if Int(payloadLength) <= 0 || Int(payloadLength) > decryptedData.count - 4 || paddingLength < 12 || paddingLength > 1024 { + + if localMessageKey != msgKeyData { + Logger.shared.log("SecretChatEncryption", "message key doesn't match (length check)") + } + + return nil + } + + if localMessageKey != msgKeyData { + Logger.shared.log("SecretChatEncryption", "message key doesn't match") + return nil + } + + let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Data in + return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength)) + } + return MemoryBuffer(data: result) + } +} + +enum SecretChatEncryptionMode { + case v1 + case v2(role: SecretChatRole) +} + +struct SecretChatEncryptionParameters { + let key: SecretChatKey + let mode: SecretChatEncryptionMode +} + +func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: MemoryBuffer) -> Data { + var payloadLength: Int32 = Int32(data.length) + var payloadData = Data() + withUnsafeBytes(of: &payloadLength, { bytes -> Void in + payloadData.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 4) + }) + payloadData.append(data.memory.assumingMemoryBound(to: UInt8.self), count: data.length) + + switch parameters.mode { + case .v1: + var msgKey = MTSha1(payloadData)! + msgKey.replaceSubrange(0 ..< (msgKey.count - 16), with: Data()) + + var randomBuf = malloc(16)! + defer { + free(randomBuf) + } + let randomBytes = randomBuf.assumingMemoryBound(to: UInt8.self) + arc4random_buf(randomBuf, 16) + + var randomIndex = 0 + while payloadData.count % 16 != 0 { + payloadData.append(randomBytes.advanced(by: randomIndex), count: 1) + randomIndex += 1 + } + + let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer) -> (Data, Data) in + return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode) + } + + let encryptedData = MTAesEncrypt(payloadData, aesKey, aesIv)! + var encryptedPayload = Data() + var keyFingerprint: Int64 = parameters.key.fingerprint + withUnsafeBytes(of: &keyFingerprint, { bytes -> Void in + encryptedPayload.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 8) + }) + encryptedPayload.append(msgKey) + encryptedPayload.append(encryptedData) + return encryptedPayload + case let .v2(role): + var randomBytes = Data(count: 128) + let randomBytesCount = randomBytes.count + randomBytes.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + arc4random_buf(bytes, randomBytesCount) + } + + var decryptedData = payloadData + var take = 0 + while take < 12 { + decryptedData.append(randomBytes.subdata(in: take ..< (take + 1))) + take += 1 + } + + while decryptedData.count % 16 != 0 { + decryptedData.append(randomBytes.subdata(in: take ..< (take + 1))) + take += 1 + } + + var remainingCount = Int(arc4random_uniform(UInt32(72 + 1 - take))) + while remainingCount % 16 != 0 { + remainingCount -= 1 + } + + for _ in 0 ..< remainingCount { + decryptedData.append(randomBytes.subdata(in: take ..< (take + 1))) + take += 1 + } + + var xValue: Int + switch role { + case .creator: + xValue = 0 + case .participant: + xValue = 8 + } + + var keyData = Data() + keyData.append(parameters.key.key.memory.assumingMemoryBound(to: UInt8.self).advanced(by: 88 + xValue), count: 32) + + keyData.append(decryptedData) + + let keyLarge = MTSha256(keyData)! + + let msgKey = keyLarge.subdata(in: 8 ..< (8 + 16)) + + let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer) -> (Data, Data) in + return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode) + } + + let encryptedData = MTAesEncrypt(decryptedData, aesKey, aesIv)! + var encryptedPayload = Data() + var keyFingerprint: Int64 = parameters.key.fingerprint + withUnsafeBytes(of: &keyFingerprint, { bytes -> Void in + encryptedPayload.append(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), count: 8) + }) + encryptedPayload.append(msgKey) + encryptedPayload.append(encryptedData) + return encryptedPayload + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatEncryptionConfig.swift b/submodules/TelegramCore/TelegramCore/SecretChatEncryptionConfig.swift new file mode 100644 index 0000000000..fce06f6105 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatEncryptionConfig.swift @@ -0,0 +1,66 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public final class SecretChatEncryptionConfig: PostboxCoding { + let g: Int32 + let p: MemoryBuffer + let version: Int32 + + public init(g: Int32, p: MemoryBuffer, version: Int32) { + self.g = g + self.p = p + self.version = version + } + + public init(decoder: PostboxDecoder) { + self.g = decoder.decodeInt32ForKey("g", orElse: 0) + self.p = decoder.decodeBytesForKey("p")! + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.g, forKey: "g") + encoder.encodeBytes(self.p, forKey: "p") + encoder.encodeInt32(self.version, forKey: "v") + } +} + +func validatedEncryptionConfig(postbox: Postbox, network: Network) -> Signal { + return network.request(Api.functions.messages.getDhConfig(version: 0, randomLength: 0)) + |> retryRequest + |> mapToSignal { result -> Signal in + switch result { + case let .dhConfig(g, p, version, _): + if !MTCheckIsSafeG(UInt32(g)) { + Logger.shared.log("SecretChatEncryptionConfig", "Invalid g") + return .complete() + } + + if !MTCheckMod(p.makeData(), UInt32(g), network.context.keychain) { + Logger.shared.log("SecretChatEncryptionConfig", "Invalid p or g") + return .complete() + } + + if !MTCheckIsSafePrime(p.makeData(), network.context.keychain) { + Logger.shared.log("SecretChatEncryptionConfig", "Invalid p") + return .never() + } + return .single(SecretChatEncryptionConfig(g: g, p: MemoryBuffer(p), version: version)) + case .dhConfigNotModified(_): + assertionFailure() + return .never() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatFileReference.swift b/submodules/TelegramCore/TelegramCore/SecretChatFileReference.swift new file mode 100644 index 0000000000..2dd9b618da --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatFileReference.swift @@ -0,0 +1,49 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +final class SecretChatFileReference: PostboxCoding { + let id: Int64 + let accessHash: Int64 + let size: Int32 + let datacenterId: Int32 + let keyFingerprint: Int32 + + init(id: Int64, accessHash: Int64, size: Int32, datacenterId: Int32, keyFingerprint: Int32) { + self.id = id + self.accessHash = accessHash + self.size = size + self.datacenterId = datacenterId + self.keyFingerprint = keyFingerprint + } + + init(decoder: PostboxDecoder) { + self.id = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + self.size = decoder.decodeInt32ForKey("s", orElse: 0) + self.datacenterId = decoder.decodeInt32ForKey("d", orElse: 0) + self.keyFingerprint = decoder.decodeInt32ForKey("f", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id, forKey: "i") + encoder.encodeInt64(self.accessHash, forKey: "a") + encoder.encodeInt32(self.size, forKey: "s") + encoder.encodeInt32(self.datacenterId, forKey: "d") + encoder.encodeInt32(self.keyFingerprint, forKey: "f") + } +} + +extension SecretChatFileReference { + convenience init?(_ file: Api.EncryptedFile) { + switch file { + case let .encryptedFile(id, accessHash, size, dcId, keyFingerprint): + self.init(id: id, accessHash: accessHash, size: size, datacenterId: dcId, keyFingerprint: keyFingerprint) + case .encryptedFileEmpty: + return nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatIncomingDecryptedOperation.swift b/submodules/TelegramCore/TelegramCore/SecretChatIncomingDecryptedOperation.swift new file mode 100644 index 0000000000..7087cb03af --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatIncomingDecryptedOperation.swift @@ -0,0 +1,66 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +struct SecretChatOperationSequenceInfo: PostboxCoding { + let topReceivedOperationIndex: Int32 + let operationIndex: Int32 + + init(topReceivedOperationIndex: Int32, operationIndex: Int32) { + self.topReceivedOperationIndex = topReceivedOperationIndex + self.operationIndex = operationIndex + } + + init(decoder: PostboxDecoder) { + self.topReceivedOperationIndex = decoder.decodeInt32ForKey("r", orElse: 0) + self.operationIndex = decoder.decodeInt32ForKey("o", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.topReceivedOperationIndex, forKey: "r") + encoder.encodeInt32(self.operationIndex, forKey: "o") + } +} + +final class SecretChatIncomingDecryptedOperation: PostboxCoding { + let timestamp: Int32 + let layer: Int32 + let sequenceInfo: SecretChatOperationSequenceInfo? + let contents: MemoryBuffer + let file: SecretChatFileReference? + + init(timestamp: Int32, layer: Int32, sequenceInfo: SecretChatOperationSequenceInfo?, contents: MemoryBuffer, file: SecretChatFileReference?) { + self.timestamp = timestamp + self.layer = layer + self.sequenceInfo = sequenceInfo + self.contents = contents + self.file = file + } + + init(decoder: PostboxDecoder) { + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + self.layer = decoder.decodeInt32ForKey("l", orElse: 0) + self.sequenceInfo = decoder.decodeObjectForKey("s", decoder: { SecretChatOperationSequenceInfo(decoder: $0) }) as? SecretChatOperationSequenceInfo + self.contents = decoder.decodeBytesForKey("c")! + self.file = decoder.decodeObjectForKey("f", decoder: { SecretChatFileReference(decoder: $0) }) as? SecretChatFileReference + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.timestamp, forKey: "t") + encoder.encodeInt32(self.layer, forKey: "l") + if let sequenceInfo = self.sequenceInfo { + encoder.encodeObject(sequenceInfo, forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + encoder.encodeBytes(self.contents, forKey: "c") + if let file = self.file { + encoder.encodeObject(file, forKey: "f") + } else { + encoder.encodeNil(forKey: "f") + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatIncomingEncryptedOperation.swift b/submodules/TelegramCore/TelegramCore/SecretChatIncomingEncryptedOperation.swift new file mode 100644 index 0000000000..d6176a3aed --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatIncomingEncryptedOperation.swift @@ -0,0 +1,92 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +enum SecretChatIncomingEncryptedOperationType: Int32 { + case message + case service + + init(_ value: Int32) { + if value == 0 { + self = .message + } else { + self = .service + } + } + + var value: Int32 { + switch self { + case .message: + return 0 + case .service: + return 1 + } + } +} + +final class SecretChatIncomingEncryptedOperation: PostboxCoding { + let peerId: PeerId + let globallyUniqueId: Int64 + let timestamp: Int32 + let type: SecretChatIncomingEncryptedOperationType + let keyFingerprint: Int64 + let contents: MemoryBuffer + let mediaFileReference: SecretChatFileReference? + + init(peerId: PeerId, globallyUniqueId: Int64, timestamp: Int32, type: SecretChatIncomingEncryptedOperationType, keyFingerprint: Int64, contents: MemoryBuffer, mediaFileReference: SecretChatFileReference?) { + self.peerId = peerId + self.globallyUniqueId = globallyUniqueId + self.timestamp = timestamp + self.type = type + self.keyFingerprint = keyFingerprint + self.contents = contents + self.mediaFileReference = mediaFileReference + } + + init(decoder: PostboxDecoder) { + self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + self.globallyUniqueId = decoder.decodeInt64ForKey("u", orElse: 0) + self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + self.type = SecretChatIncomingEncryptedOperationType(decoder.decodeInt32ForKey("k", orElse: 0)) + self.keyFingerprint = decoder.decodeInt64ForKey("f", orElse: 0) + self.contents = decoder.decodeBytesForKey("c")! + self.mediaFileReference = decoder.decodeObjectForKey("m", decoder: { SecretChatFileReference(decoder: $0) }) as? SecretChatFileReference + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.peerId.toInt64(), forKey: "p") + encoder.encodeInt64(self.globallyUniqueId, forKey: "u") + encoder.encodeInt32(self.timestamp, forKey: "t") + encoder.encodeInt32(self.type.value, forKey: "k") + encoder.encodeInt64(self.keyFingerprint, forKey: "f") + encoder.encodeBytes(self.contents, forKey: "c") + if let mediaFileReference = self.mediaFileReference { + encoder.encodeObject(mediaFileReference, forKey: "m") + } else { + encoder.encodeNil(forKey: "m") + } + } +} + +private func keyFingerprintFromBytes(_ bytes: Buffer) -> Int64 { + if let memory = bytes.data, bytes.size >= 4 { + var fingerprint: Int64 = 0 + memcpy(&fingerprint, memory, 8) + return fingerprint + } + return 0 +} + +extension SecretChatIncomingEncryptedOperation { + convenience init(message: Api.EncryptedMessage) { + switch message { + case let .encryptedMessage(randomId, chatId, date, bytes, file): + self.init(peerId: PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId), globallyUniqueId: randomId, timestamp: date, type: .message, keyFingerprint: keyFingerprintFromBytes(bytes), contents: MemoryBuffer(bytes), mediaFileReference: SecretChatFileReference(file)) + case let .encryptedMessageService(randomId, chatId, date, bytes): + self.init(peerId: PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId), globallyUniqueId: randomId, timestamp: date, type: .service, keyFingerprint: keyFingerprintFromBytes(bytes), contents: MemoryBuffer(bytes), mediaFileReference: nil) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatKeychain.swift b/submodules/TelegramCore/TelegramCore/SecretChatKeychain.swift new file mode 100644 index 0000000000..90959dfe61 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatKeychain.swift @@ -0,0 +1,188 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum SecretChatKeyValidity: PostboxCoding, Equatable { + case indefinite + case sequenceBasedIndexRange(fromCanonicalIndex: Int32) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case 0: + self = .indefinite + case 1: + self = .sequenceBasedIndexRange(fromCanonicalIndex: decoder.decodeInt32ForKey("l", orElse: 0)) + default: + assertionFailure() + self = .sequenceBasedIndexRange(fromCanonicalIndex: Int32.max) + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .indefinite: + encoder.encodeInt32(0, forKey: "r") + case let .sequenceBasedIndexRange(fromCanonicalIndex): + encoder.encodeInt32(1, forKey: "r") + encoder.encodeInt32(fromCanonicalIndex, forKey: "l") + } + } + + public static func ==(lhs: SecretChatKeyValidity, rhs: SecretChatKeyValidity) -> Bool { + switch lhs { + case .indefinite: + if case .indefinite = rhs { + return true + } else { + return false + } + case let .sequenceBasedIndexRange(fromCanonicalIndex): + if case .sequenceBasedIndexRange(fromCanonicalIndex) = rhs { + return true + } else { + return false + } + } + } +} + +public final class SecretChatKey: PostboxCoding, Equatable { + let fingerprint: Int64 + let key: MemoryBuffer + let validity: SecretChatKeyValidity + let useCount: Int32 + + public init(fingerprint: Int64, key: MemoryBuffer, validity: SecretChatKeyValidity, useCount: Int32) { + self.fingerprint = fingerprint + self.key = key + self.validity = validity + self.useCount = useCount + } + + public init(decoder: PostboxDecoder) { + self.fingerprint = decoder.decodeInt64ForKey("f", orElse: 0) + self.key = decoder.decodeBytesForKey("k")! + self.validity = decoder.decodeObjectForKey("v", decoder: { SecretChatKeyValidity(decoder: $0) }) as! SecretChatKeyValidity + self.useCount = decoder.decodeInt32ForKey("u", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.fingerprint, forKey: "f") + encoder.encodeBytes(self.key, forKey: "k") + encoder.encodeObject(self.validity, forKey: "v") + encoder.encodeInt32(self.useCount, forKey: "u") + } + + func withIncrementedUseCount() -> SecretChatKey { + return SecretChatKey(fingerprint: self.fingerprint, key: self.key, validity: self.validity, useCount: self.useCount + 1) + } + + public static func ==(lhs: SecretChatKey, rhs: SecretChatKey) -> Bool { + if lhs.fingerprint != rhs.fingerprint { + return false + } + if lhs.validity != rhs.validity { + return false + } + if lhs.useCount != rhs.useCount { + return false + } + return true + } +} + +public final class SecretChatKeychain: PostboxCoding, Equatable { + let keys: [SecretChatKey] + + public init(keys: [SecretChatKey]) { + self.keys = keys + } + + public init(decoder: PostboxDecoder) { + self.keys = decoder.decodeObjectArrayWithDecoderForKey("k") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.keys, forKey: "k") + } + + func key(fingerprint: Int64) -> SecretChatKey? { + for key in self.keys { + if key.fingerprint == fingerprint { + return key + } + } + return nil + } + + func indefinitelyValidKey() -> SecretChatKey? { + for key in self.keys { + if case .indefinite = key.validity { + return key + } + } + return nil + } + + func latestKey(validForSequenceBasedCanonicalIndex index: Int32) -> SecretChatKey? { + var maxFromCanonicalIndex: (Int, Int32)? + for i in 0 ..< self.keys.count { + switch self.keys[i].validity { + case .indefinite: + break + case let .sequenceBasedIndexRange(fromCanonicalIndex): + if index >= fromCanonicalIndex { + if maxFromCanonicalIndex == nil || maxFromCanonicalIndex!.1 < fromCanonicalIndex { + maxFromCanonicalIndex = (i, fromCanonicalIndex) + } + } + } + } + + if let (keyIndex, _) = maxFromCanonicalIndex { + return self.keys[keyIndex] + } + + for i in 0 ..< self.keys.count { + switch self.keys[i].validity { + case .indefinite: + return self.keys[i] + default: + break + } + } + + return nil + } + + func withUpdatedKey(fingerprint: Int64, _ f: (SecretChatKey?) -> SecretChatKey?) -> SecretChatKeychain { + var keys = self.keys + var found = false + for i in 0 ..< keys.count { + if keys[i].fingerprint == fingerprint { + found = true + let updatedKey = f(keys[i]) + if let updatedKey = updatedKey { + keys[i] = updatedKey + } else { + keys.remove(at: i) + } + break + } + } + if !found { + let updatedKey = f(nil) + if let updatedKey = updatedKey { + keys.append(updatedKey) + } + } + return SecretChatKeychain(keys: keys) + } + + public static func ==(lhs: SecretChatKeychain, rhs: SecretChatKeychain) -> Bool { + return lhs.keys == rhs.keys + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatLayerNegotiation.swift b/submodules/TelegramCore/TelegramCore/SecretChatLayerNegotiation.swift new file mode 100644 index 0000000000..2078aecaf6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatLayerNegotiation.swift @@ -0,0 +1,63 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private let topSupportedLayer: SecretChatSequenceBasedLayer = .layer73 + +func secretChatCommonSupportedLayer(remoteLayer: Int32) -> SecretChatSequenceBasedLayer { + switch remoteLayer { + case 46: + return .layer46 + case 73: + return .layer73 + default: + return topSupportedLayer + } +} + +func secretChatAddReportCurrentLayerSupportOperationAndUpdateRequestedLayer(transaction: Transaction, peerId: PeerId, state: SecretChatState) -> SecretChatState { + switch state.embeddedState { + case .basicLayer: + var updatedState = state + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: .layer8, actionGloballyUniqueId: arc4random64(), layerSupport: topSupportedLayer.rawValue), state: updatedState) + return updatedState + case let .sequenceBasedLayer(sequenceState): + var updatedState = state + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: sequenceState.layerNegotiationState.activeLayer.secretChatLayer, actionGloballyUniqueId: arc4random64(), layerSupport: topSupportedLayer.rawValue), state: updatedState) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedLayerNegotiationState(sequenceState.layerNegotiationState.withUpdatedLocallyRequestedLayer(topSupportedLayer.rawValue)))) + return updatedState + default: + return state + } +} + +func secretChatCheckLayerNegotiationIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState) -> SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if sequenceState.layerNegotiationState.activeLayer != topSupportedLayer { + var updatedState = state + + if let remotelyRequestedLayer = sequenceState.layerNegotiationState.remotelyRequestedLayer { + let updatedSequenceState = sequenceState.withUpdatedLayerNegotiationState(sequenceState.layerNegotiationState.withUpdatedActiveLayer(secretChatCommonSupportedLayer(remoteLayer: remotelyRequestedLayer))) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(updatedSequenceState)) + } + + if (sequenceState.layerNegotiationState.locallyRequestedLayer ?? 0) < topSupportedLayer.rawValue { + updatedState = secretChatAddReportCurrentLayerSupportOperationAndUpdateRequestedLayer(transaction: transaction, peerId: peerId, state: updatedState) + } + + return updatedState + } else { + return state + } + case .basicLayer: + return state + default: + return state + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatOutgoingOperation.swift b/submodules/TelegramCore/TelegramCore/SecretChatOutgoingOperation.swift new file mode 100644 index 0000000000..9077e8be15 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatOutgoingOperation.swift @@ -0,0 +1,312 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private enum SecretChatOutgoingFileValue: Int32 { + case remote = 0 + case uploadedRegular = 1 + case uploadedLarge = 2 +} + +enum SecretChatOutgoingFileReference: PostboxCoding { + case remote(id: Int64, accessHash: Int64) + case uploadedRegular(id: Int64, partCount: Int32, md5Digest: String, keyFingerprint: Int32) + case uploadedLarge(id: Int64, partCount: Int32, keyFingerprint: Int32) + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case SecretChatOutgoingFileValue.remote.rawValue: + self = .remote(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("a", orElse: 0)) + case SecretChatOutgoingFileValue.uploadedRegular.rawValue: + self = .uploadedRegular(id: decoder.decodeInt64ForKey("i", orElse: 0), partCount: decoder.decodeInt32ForKey("p", orElse: 0), md5Digest: decoder.decodeStringForKey("d", orElse: ""), keyFingerprint: decoder.decodeInt32ForKey("f", orElse: 0)) + case SecretChatOutgoingFileValue.uploadedLarge.rawValue: + self = .uploadedLarge(id: decoder.decodeInt64ForKey("i", orElse: 0), partCount: decoder.decodeInt32ForKey("p", orElse: 0), keyFingerprint: decoder.decodeInt32ForKey("f", orElse: 0)) + default: + assertionFailure() + self = .remote(id: 0, accessHash: 0) + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .remote(id, accessHash): + encoder.encodeInt32(SecretChatOutgoingFileValue.remote.rawValue, forKey: "v") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "a") + case let .uploadedRegular(id, partCount, md5Digest, keyFingerprint): + encoder.encodeInt32(SecretChatOutgoingFileValue.uploadedRegular.rawValue, forKey: "v") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt32(partCount, forKey: "p") + encoder.encodeString(md5Digest, forKey: "d") + encoder.encodeInt32(keyFingerprint, forKey: "f") + case let .uploadedLarge(id, partCount, keyFingerprint): + encoder.encodeInt32(SecretChatOutgoingFileValue.uploadedLarge.rawValue, forKey: "v") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt32(partCount, forKey: "p") + encoder.encodeInt32(keyFingerprint, forKey: "f") + } + } +} + +struct SecretChatOutgoingFile: PostboxCoding { + let reference: SecretChatOutgoingFileReference + let size: Int32 + let key: SecretFileEncryptionKey + + init(reference: SecretChatOutgoingFileReference, size: Int32, key: SecretFileEncryptionKey) { + self.reference = reference + self.size = size + self.key = key + } + + init(decoder: PostboxDecoder) { + self.reference = decoder.decodeObjectForKey("r", decoder: { SecretChatOutgoingFileReference(decoder: $0) }) as! SecretChatOutgoingFileReference + self.size = decoder.decodeInt32ForKey("s", orElse: 0) + self.key = SecretFileEncryptionKey(aesKey: decoder.decodeBytesForKey("k")!.makeData(), aesIv: decoder.decodeBytesForKey("i")!.makeData()) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.reference, forKey: "r") + encoder.encodeInt32(self.size, forKey: "s") + encoder.encodeBytes(MemoryBuffer(data: self.key.aesKey), forKey: "k") + encoder.encodeBytes(MemoryBuffer(data: self.key.aesIv), forKey: "i") + } +} + +public enum SecretChatSequenceBasedLayer: Int32 { + case layer46 = 46 + case layer73 = 73 + + var secretChatLayer: SecretChatLayer { + switch self { + case .layer46: + return .layer46 + case .layer73: + return .layer73 + } + } +} + +private enum SecretChatOutgoingOperationValue: Int32 { + case initialHandshakeAccept = 0 + case sendMessage = 1 + case readMessagesContent = 2 + case deleteMessages = 3 + case screenshotMessages = 4 + case clearHistory = 5 + case resendOperations = 6 + case reportLayerSupport = 7 + case pfsRequestKey = 8 + case pfsAcceptKey = 9 + case pfsAbortSession = 10 + case pfsCommitKey = 11 + case noop = 12 + case setMessageAutoremoveTimeout = 13 + case terminate = 14 +} + +enum SecretChatOutgoingOperationContents: PostboxCoding { + case initialHandshakeAccept(gA: MemoryBuffer, accessHash: Int64, b: MemoryBuffer) + case sendMessage(layer: SecretChatLayer, id: MessageId, file: SecretChatOutgoingFile?) + case readMessagesContent(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64]) + case deleteMessages(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64]) + case screenshotMessages(layer: SecretChatLayer, actionGloballyUniqueId: Int64, globallyUniqueIds: [Int64], messageId: MessageId) + case clearHistory(layer: SecretChatLayer, actionGloballyUniqueId: Int64) + case resendOperations(layer : SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, fromSeqNo: Int32, toSeqNo: Int32) + case reportLayerSupport(layer: SecretChatLayer, actionGloballyUniqueId: Int64, layerSupport: Int32) + case pfsRequestKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, a: MemoryBuffer) + case pfsAcceptKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, gA: MemoryBuffer, b: MemoryBuffer) + case pfsAbortSession(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64) + case pfsCommitKey(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, keyFingerprint: Int64) + case noop(layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64) + case setMessageAutoremoveTimeout(layer: SecretChatLayer, actionGloballyUniqueId: Int64, timeout: Int32, messageId: MessageId) + case terminate(reportSpam: Bool) + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SecretChatOutgoingOperationValue.initialHandshakeAccept.rawValue: + self = .initialHandshakeAccept(gA: decoder.decodeBytesForKey("g")!, accessHash: decoder.decodeInt64ForKey("h", orElse: 0), b: decoder.decodeBytesForKey("b")!) + case SecretChatOutgoingOperationValue.sendMessage.rawValue: + self = .sendMessage(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0)), file: decoder.decodeObjectForKey("f", decoder: { SecretChatOutgoingFile(decoder: $0) }) as? SecretChatOutgoingFile) + case SecretChatOutgoingOperationValue.readMessagesContent.rawValue: + self = .readMessagesContent(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) + case SecretChatOutgoingOperationValue.deleteMessages.rawValue: + self = .deleteMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u")) + case SecretChatOutgoingOperationValue.screenshotMessages.rawValue: + self = .screenshotMessages(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), globallyUniqueIds: decoder.decodeInt64ArrayForKey("u"), messageId: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))) + case SecretChatOutgoingOperationValue.clearHistory.rawValue: + self = .clearHistory(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0)) + case SecretChatOutgoingOperationValue.resendOperations.rawValue: + self = .resendOperations(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), fromSeqNo: decoder.decodeInt32ForKey("f", orElse: 0), toSeqNo: decoder.decodeInt32ForKey("t", orElse: 0)) + case SecretChatOutgoingOperationValue.reportLayerSupport.rawValue: + self = .reportLayerSupport(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), layerSupport: decoder.decodeInt32ForKey("l", orElse: 0)) + case SecretChatOutgoingOperationValue.pfsRequestKey.rawValue: + self = .pfsRequestKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), a: decoder.decodeBytesForKey("a")!) + case SecretChatOutgoingOperationValue.pfsAcceptKey.rawValue: + self = .pfsAcceptKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), gA: decoder.decodeBytesForKey("g")!, b: decoder.decodeBytesForKey("b")!) + case SecretChatOutgoingOperationValue.pfsAbortSession.rawValue: + self = .pfsAbortSession(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0)) + case SecretChatOutgoingOperationValue.pfsCommitKey.rawValue: + self = .pfsCommitKey(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), rekeySessionId: decoder.decodeInt64ForKey("s", orElse: 0), keyFingerprint: decoder.decodeInt64ForKey("f", orElse: 0)) + case SecretChatOutgoingOperationValue.noop.rawValue: + self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0)) + case SecretChatOutgoingOperationValue.setMessageAutoremoveTimeout.rawValue: + self = .setMessageAutoremoveTimeout(layer: SecretChatLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: decoder.decodeInt64ForKey("i", orElse: 0), timeout: decoder.decodeInt32ForKey("t", orElse: 0), messageId: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))) + case SecretChatOutgoingOperationValue.terminate.rawValue: + self = .terminate(reportSpam: decoder.decodeInt32ForKey("rs", orElse: 0) != 0) + default: + self = .noop(layer: SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("l", orElse: 0))!, actionGloballyUniqueId: 0) + assertionFailure() + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .initialHandshakeAccept(gA, accessHash, b): + encoder.encodeInt32(SecretChatOutgoingOperationValue.initialHandshakeAccept.rawValue, forKey: "r") + encoder.encodeBytes(gA, forKey: "g") + encoder.encodeInt64(accessHash, forKey: "h") + encoder.encodeBytes(b, forKey: "b") + case let .sendMessage(layer, id, file): + encoder.encodeInt32(SecretChatOutgoingOperationValue.sendMessage.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(id.peerId.toInt64(), forKey: "i.p") + encoder.encodeInt32(id.namespace, forKey: "i.n") + encoder.encodeInt32(id.id, forKey: "i.i") + if let file = file { + encoder.encodeObject(file, forKey: "f") + } else { + encoder.encodeNil(forKey: "f") + } + case let .readMessagesContent(layer, actionGloballyUniqueId, globallyUniqueIds): + encoder.encodeInt32(SecretChatOutgoingOperationValue.readMessagesContent.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64Array(globallyUniqueIds, forKey: "u") + case let .deleteMessages(layer, actionGloballyUniqueId, globallyUniqueIds): + encoder.encodeInt32(SecretChatOutgoingOperationValue.deleteMessages.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64Array(globallyUniqueIds, forKey: "u") + case let .screenshotMessages(layer, actionGloballyUniqueId, globallyUniqueIds, messageId): + encoder.encodeInt32(SecretChatOutgoingOperationValue.screenshotMessages.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64Array(globallyUniqueIds, forKey: "u") + encoder.encodeInt64(messageId.peerId.toInt64(), forKey: "m.p") + encoder.encodeInt32(messageId.namespace, forKey: "m.n") + encoder.encodeInt32(messageId.id, forKey: "m.i") + case let .clearHistory(layer, actionGloballyUniqueId): + encoder.encodeInt32(SecretChatOutgoingOperationValue.clearHistory.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + case let .resendOperations(layer, actionGloballyUniqueId, fromSeqNo, toSeqNo): + encoder.encodeInt32(SecretChatOutgoingOperationValue.resendOperations.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt32(fromSeqNo, forKey: "f") + encoder.encodeInt32(toSeqNo, forKey: "t") + case let .reportLayerSupport(layer, actionGloballyUniqueId, layerSupport): + encoder.encodeInt32(SecretChatOutgoingOperationValue.reportLayerSupport.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt32(layerSupport, forKey: "l") + case let .pfsRequestKey(layer, actionGloballyUniqueId, rekeySessionId, a): + encoder.encodeInt32(SecretChatOutgoingOperationValue.pfsRequestKey.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64(rekeySessionId, forKey: "s") + encoder.encodeBytes(a, forKey: "a") + case let .pfsAcceptKey(layer, actionGloballyUniqueId, rekeySessionId, gA, b): + encoder.encodeInt32(SecretChatOutgoingOperationValue.pfsAcceptKey.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64(rekeySessionId, forKey: "s") + encoder.encodeBytes(gA, forKey: "g") + encoder.encodeBytes(b, forKey: "b") + case let .pfsAbortSession(layer, actionGloballyUniqueId, rekeySessionId): + encoder.encodeInt32(SecretChatOutgoingOperationValue.pfsAbortSession.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64(rekeySessionId, forKey: "s") + case let .pfsCommitKey(layer, actionGloballyUniqueId, rekeySessionId, keyFingerprint): + encoder.encodeInt32(SecretChatOutgoingOperationValue.pfsCommitKey.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt64(rekeySessionId, forKey: "s") + encoder.encodeInt64(keyFingerprint, forKey: "f") + case let .noop(layer, actionGloballyUniqueId): + encoder.encodeInt32(SecretChatOutgoingOperationValue.noop.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + case let .setMessageAutoremoveTimeout(layer, actionGloballyUniqueId, timeout, messageId): + encoder.encodeInt32(SecretChatOutgoingOperationValue.setMessageAutoremoveTimeout.rawValue, forKey: "r") + encoder.encodeInt32(layer.rawValue, forKey: "l") + encoder.encodeInt64(actionGloballyUniqueId, forKey: "i") + encoder.encodeInt32(timeout, forKey: "t") + encoder.encodeInt64(messageId.peerId.toInt64(), forKey: "m.p") + encoder.encodeInt32(messageId.namespace, forKey: "m.n") + encoder.encodeInt32(messageId.id, forKey: "m.i") + case let .terminate(reportSpam): + encoder.encodeInt32(SecretChatOutgoingOperationValue.terminate.rawValue, forKey: "r") + encoder.encodeInt32(reportSpam ? 1 : 0, forKey: "rs") + } + } +} + +final class SecretChatOutgoingOperation: PostboxCoding { + let contents: SecretChatOutgoingOperationContents + let mutable: Bool + let delivered: Bool + + init(contents: SecretChatOutgoingOperationContents, mutable: Bool, delivered: Bool) { + self.contents = contents + self.mutable = mutable + self.delivered = delivered + } + + init(decoder: PostboxDecoder) { + self.contents = decoder.decodeObjectForKey("c", decoder: { SecretChatOutgoingOperationContents(decoder: $0) }) as! SecretChatOutgoingOperationContents + self.mutable = decoder.decodeInt32ForKey("m", orElse: 0) != 0 + self.delivered = decoder.decodeInt32ForKey("d", orElse: 0) != 0 + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.contents, forKey: "c") + encoder.encodeInt32(self.mutable ? 1 : 0, forKey: "m") + encoder.encodeInt32(self.delivered ? 1 : 0, forKey: "d") + } + + func withUpdatedDelivered(_ delivered: Bool) -> SecretChatOutgoingOperation { + return SecretChatOutgoingOperation(contents: self.contents, mutable: self.mutable, delivered: delivered) + } +} + +extension SecretChatOutgoingFileReference { + init?(_ apiFile: Api.InputEncryptedFile) { + switch apiFile { + case let .inputEncryptedFile(id, accessHash): + self = .remote(id: id, accessHash: accessHash) + case let .inputEncryptedFileBigUploaded(id, parts, keyFingerprint): + self = .uploadedLarge(id: id, partCount: parts, keyFingerprint: keyFingerprint) + case let .inputEncryptedFileUploaded(id, parts, md5Checksum, keyFingerprint): + self = .uploadedRegular(id: id, partCount: parts, md5Digest: md5Checksum, keyFingerprint: keyFingerprint) + case .inputEncryptedFileEmpty: + return nil + } + } + + var apiInputFile: Api.InputEncryptedFile { + switch self { + case let .remote(id, accessHash): + return .inputEncryptedFile(id: id, accessHash: accessHash) + case let .uploadedRegular(id, partCount, md5Digest, keyFingerprint): + return .inputEncryptedFileUploaded(id: id, parts: partCount, md5Checksum: md5Digest, keyFingerprint: keyFingerprint) + case let .uploadedLarge(id, partCount, keyFingerprint): + return .inputEncryptedFileBigUploaded(id: id, parts: partCount, keyFingerprint: keyFingerprint) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatRekeySession.swift b/submodules/TelegramCore/TelegramCore/SecretChatRekeySession.swift new file mode 100644 index 0000000000..888a897cc6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatRekeySession.swift @@ -0,0 +1,140 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private let keyUseCountThreshold: Int32 = 100 + +func secretChatInitiateRekeySessionIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState) -> SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if let _ = sequenceState.rekeyState { + return state + } + let tagLocalIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing) + let canonicalIndex = sequenceState.canonicalOutgoingOperationIndex(tagLocalIndex) + if let key = state.keychain.latestKey(validForSequenceBasedCanonicalIndex: canonicalIndex), key.useCount >= keyUseCountThreshold { + let sessionId = arc4random64() + let aBytes = malloc(256)! + let _ = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self)) + let a = MemoryBuffer(memory: aBytes, capacity: 256, length: 256, freeWhenDone: true) + + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsRequestKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: sessionId, a: a), mutable: true, delivered: false)) + return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: sessionId, data: .requesting)))) + } + default: + break + } + return state +} + +func secretChatAdvanceRekeySessionIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState, action: SecretChatRekeyServiceAction) -> SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + switch action { + case let .pfsAbortSession(rekeySessionId): + if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId { + return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))) + } + case let .pfsAcceptKey(rekeySessionId, gB, remoteKeyFingerprint): + if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId { + switch rekeySession.data { + case let .requested(a, config): + var gValue: Int32 = config.g.byteSwapped + let p = config.p.makeData() + + let aData = a.makeData() + if !MTCheckIsSafeGAOrB(gB.makeData(), p) { + return state.withUpdatedEmbeddedState(.terminated) + } + + var key = MTExp(gB.makeData(), aData, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + assert(remoteKeyFingerprint == keyFingerprint) + + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsCommitKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, keyFingerprint: keyFingerprint), mutable: true, delivered: false)) + + let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing) + let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex) + + return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in + return SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0) + })) + default: + assertionFailure() + break + } + } + case let .pfsCommitKey(rekeySessionId, keyFingerprint): + if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId { + if case let .accepted(key, localKeyFingerprint) = rekeySession.data, keyFingerprint == localKeyFingerprint { + let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing) + let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex) + + let updatedState = state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in + return SecretChatKey(fingerprint: keyFingerprint, key: key, validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0) + })) + + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .noop(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64()), mutable: true, delivered: false)) + + return updatedState + } else { + assertionFailure() + } + } else { + assertionFailure() + } + case let .pfsRequestKey(rekeySessionId, gA): + var acceptSession = true + if let rekeySession = sequenceState.rekeyState { + switch rekeySession.data { + case .requesting, .requested: + if rekeySessionId < rekeySession.id { + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAbortSession(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id), mutable: true, delivered: false)) + } else { + acceptSession = false + } + case .accepting, .accepted: + break + } + } + + if acceptSession { + let bBytes = malloc(256)! + let _ = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self)) + let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true) + + let rekeySession = SecretChatRekeySessionState(id: rekeySessionId, data: .accepting) + + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAcceptKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, gA: gA, b: b), mutable: true, delivered: false)) + return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(rekeySession))) + } + } + default: + break + } + return state +} diff --git a/submodules/TelegramCore/TelegramCore/SecretChatState.swift b/submodules/TelegramCore/TelegramCore/SecretChatState.swift new file mode 100644 index 0000000000..4fca04dae7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatState.swift @@ -0,0 +1,636 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum SecretChatRole: Int32 { + case creator + case participant +} + +enum SecretChatLayer: Int32 { + case layer8 = 8 + case layer46 = 46 + case layer73 = 73 +} + +public struct SecretChatKeySha1Fingerprint: PostboxCoding, Equatable { + public let k0: Int64 + public let k1: Int64 + public let k2: Int32 + + public init(digest: Data) { + assert(digest.count == 20) + var k0: Int64 = 0 + var k1: Int64 = 0 + var k2: Int32 = 0 + digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + k0 = bytes.pointee + k1 = bytes.advanced(by: 1).pointee + } + digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + k2 = bytes.advanced(by: 4).pointee + } + self.k0 = k0 + self.k1 = k1 + self.k2 = k2 + } + + public init(k0: Int64, k1: Int64, k2: Int32) { + self.k0 = k0 + self.k1 = k1 + self.k2 = k2 + } + + public init(decoder: PostboxDecoder) { + self.k0 = decoder.decodeInt64ForKey("k0", orElse: 0) + self.k1 = decoder.decodeInt64ForKey("k1", orElse: 0) + self.k2 = decoder.decodeInt32ForKey("k2", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.k0, forKey: "k0") + encoder.encodeInt64(self.k1, forKey: "k1") + encoder.encodeInt32(self.k2, forKey: "k2") + } + + public func data() -> Data { + var data = Data() + data.count = 20 + data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + bytes.pointee = self.k0 + bytes.advanced(by: 1).pointee = self.k1 + } + data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + bytes.advanced(by: 4).pointee = self.k2 + } + return data + } + + public static func ==(lhs: SecretChatKeySha1Fingerprint, rhs: SecretChatKeySha1Fingerprint) -> Bool { + if lhs.k0 != rhs.k0 { + return false + } + if lhs.k1 != rhs.k1 { + return false + } + if lhs.k2 != rhs.k2 { + return false + } + return true + } +} + +public struct SecretChatKeySha256Fingerprint: PostboxCoding, Equatable { + public let k0: Int64 + public let k1: Int64 + public let k2: Int64 + public let k3: Int64 + + public init(digest: Data) { + assert(digest.count == 32) + var k0: Int64 = 0 + var k1: Int64 = 0 + var k2: Int64 = 0 + var k3: Int64 = 0 + digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + k0 = bytes.pointee + k1 = bytes.advanced(by: 1).pointee + k2 = bytes.advanced(by: 2).pointee + k3 = bytes.advanced(by: 3).pointee + } + self.k0 = k0 + self.k1 = k1 + self.k2 = k2 + self.k3 = k3 + } + + public init(k0: Int64, k1: Int64, k2: Int64, k3: Int64) { + self.k0 = k0 + self.k1 = k1 + self.k2 = k2 + self.k3 = k3 + } + + public init(decoder: PostboxDecoder) { + self.k0 = decoder.decodeInt64ForKey("k0", orElse: 0) + self.k1 = decoder.decodeInt64ForKey("k1", orElse: 0) + self.k2 = decoder.decodeInt64ForKey("k2", orElse: 0) + self.k3 = decoder.decodeInt64ForKey("k3", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.k0, forKey: "k0") + encoder.encodeInt64(self.k1, forKey: "k1") + encoder.encodeInt64(self.k2, forKey: "k2") + encoder.encodeInt64(self.k3, forKey: "k3") + } + + public func data() -> Data { + var data = Data() + data.count = 32 + data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + bytes.pointee = self.k0 + bytes.advanced(by: 1).pointee = self.k1 + bytes.advanced(by: 2).pointee = self.k2 + bytes.advanced(by: 3).pointee = self.k3 + } + return data + } + + public static func ==(lhs: SecretChatKeySha256Fingerprint, rhs: SecretChatKeySha256Fingerprint) -> Bool { + if lhs.k0 != rhs.k0 { + return false + } + if lhs.k1 != rhs.k1 { + return false + } + if lhs.k2 != rhs.k2 { + return false + } + if lhs.k3 != rhs.k3 { + return false + } + return true + } +} + +public struct SecretChatKeyFingerprint: PostboxCoding, Equatable { + public let sha1: SecretChatKeySha1Fingerprint + public let sha256: SecretChatKeySha256Fingerprint + + public init(sha1: SecretChatKeySha1Fingerprint, sha256: SecretChatKeySha256Fingerprint) { + self.sha1 = sha1 + self.sha256 = sha256 + } + + public init(decoder: PostboxDecoder) { + self.sha1 = decoder.decodeObjectForKey("1", decoder: { SecretChatKeySha1Fingerprint(decoder: $0) }) as! SecretChatKeySha1Fingerprint + self.sha256 = decoder.decodeObjectForKey("2", decoder: { SecretChatKeySha256Fingerprint(decoder: $0) }) as! SecretChatKeySha256Fingerprint + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.sha1, forKey: "1") + encoder.encodeObject(self.sha256, forKey: "2") + } + + public static func ==(lhs: SecretChatKeyFingerprint, rhs: SecretChatKeyFingerprint) -> Bool { + return lhs.sha1 == rhs.sha1 && lhs.sha256 == rhs.sha256 + } +} + +public enum SecretChatEmbeddedPeerState: Int32 { + case terminated = 0 + case handshake = 1 + case active = 2 +} + +private enum SecretChatEmbeddedStateValue: Int32 { + case terminated = 0 + case handshake = 1 + case basicLayer = 2 + case sequenceBasedLayer = 3 +} + +public enum SecretChatHandshakeState: PostboxCoding, Equatable { + case accepting + case requested(g: Int32, p: MemoryBuffer, a: MemoryBuffer) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case 0: + self = .accepting + case 1: + self = .requested(g: decoder.decodeInt32ForKey("g", orElse: 0), p: decoder.decodeBytesForKey("p")!, a: decoder.decodeBytesForKey("a")!) + default: + self = .accepting + assertionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .accepting: + encoder.encodeInt32(0, forKey: "r") + case let .requested(g, p, a): + encoder.encodeInt32(1, forKey: "r") + encoder.encodeInt32(g, forKey: "g") + encoder.encodeBytes(p, forKey: "p") + encoder.encodeBytes(a, forKey: "a") + } + } + + public static func ==(lhs: SecretChatHandshakeState, rhs: SecretChatHandshakeState) -> Bool { + switch lhs { + case .accepting: + if case .accepting = rhs { + return true + } else { + return false + } + case let .requested(g, p, a): + if case .requested(g, p, a) = rhs { + return true + } else { + return false + } + } + } +} + +public struct SecretChatLayerNegotiationState: PostboxCoding, Equatable { + let activeLayer: SecretChatSequenceBasedLayer + let locallyRequestedLayer: Int32? + let remotelyRequestedLayer: Int32? + + public init(activeLayer: SecretChatSequenceBasedLayer, locallyRequestedLayer: Int32?, remotelyRequestedLayer: Int32?) { + self.activeLayer = activeLayer + self.locallyRequestedLayer = locallyRequestedLayer + self.remotelyRequestedLayer = remotelyRequestedLayer + } + + public init(decoder: PostboxDecoder) { + self.activeLayer = SecretChatSequenceBasedLayer(rawValue: decoder.decodeInt32ForKey("a", orElse: 0)) ?? .layer46 + self.locallyRequestedLayer = decoder.decodeOptionalInt32ForKey("lr") + self.remotelyRequestedLayer = decoder.decodeOptionalInt32ForKey("rr") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.activeLayer.rawValue, forKey: "a") + if let locallyRequestedLayer = self.locallyRequestedLayer { + encoder.encodeInt32(locallyRequestedLayer, forKey: "lr") + } else { + encoder.encodeNil(forKey: "lr") + } + if let remotelyRequestedLayer = self.remotelyRequestedLayer { + encoder.encodeInt32(remotelyRequestedLayer, forKey: "rr") + } else { + encoder.encodeNil(forKey: "rr") + } + } + + public static func ==(lhs: SecretChatLayerNegotiationState, rhs: SecretChatLayerNegotiationState) -> Bool { + if lhs.activeLayer != rhs.activeLayer { + return false + } + if lhs.locallyRequestedLayer != rhs.locallyRequestedLayer { + return false + } + if lhs.remotelyRequestedLayer != rhs.remotelyRequestedLayer { + return false + } + return true + } + + func withUpdatedActiveLayer(_ activeLayer: SecretChatSequenceBasedLayer) -> SecretChatLayerNegotiationState { + return SecretChatLayerNegotiationState(activeLayer: activeLayer, locallyRequestedLayer: self.locallyRequestedLayer, remotelyRequestedLayer: self.remotelyRequestedLayer) + } + + func withUpdatedLocallyRequestedLayer(_ locallyRequestedLayer: Int32?) -> SecretChatLayerNegotiationState { + return SecretChatLayerNegotiationState(activeLayer: self.activeLayer, locallyRequestedLayer: locallyRequestedLayer, remotelyRequestedLayer: self.remotelyRequestedLayer) + } + + func withUpdatedRemotelyRequestedLayer(_ remotelyRequestedLayer: Int32?) -> SecretChatLayerNegotiationState { + return SecretChatLayerNegotiationState(activeLayer: self.activeLayer, locallyRequestedLayer: self.locallyRequestedLayer, remotelyRequestedLayer: remotelyRequestedLayer) + } +} + +private enum SecretChatRekeySessionDataValue: Int32 { + case requesting = 0 + case requested = 1 + case accepting = 2 + case accepted = 3 +} + +public enum SecretChatRekeySessionData: PostboxCoding, Equatable { + case requesting + case requested(a: MemoryBuffer, config: SecretChatEncryptionConfig) + case accepting + case accepted(key: MemoryBuffer, keyFingerprint: Int64) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SecretChatRekeySessionDataValue.requesting.rawValue: + self = .requesting + case SecretChatRekeySessionDataValue.requested.rawValue: + self = .requested(a: decoder.decodeBytesForKey("a")!, config: decoder.decodeObjectForKey("c", decoder: { SecretChatEncryptionConfig(decoder: $0) }) as! SecretChatEncryptionConfig) + case SecretChatRekeySessionDataValue.accepting.rawValue: + self = .accepting + case SecretChatRekeySessionDataValue.accepted.rawValue: + self = .accepted(key: decoder.decodeBytesForKey("k")!, keyFingerprint: decoder.decodeInt64ForKey("f", orElse: 0)) + default: + preconditionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .requesting: + encoder.encodeInt32(SecretChatRekeySessionDataValue.requesting.rawValue, forKey: "r") + case let .requested(a, config): + encoder.encodeInt32(SecretChatRekeySessionDataValue.requested.rawValue, forKey: "r") + encoder.encodeBytes(a, forKey: "a") + encoder.encodeObject(config, forKey: "c") + case .accepting: + encoder.encodeInt32(SecretChatRekeySessionDataValue.accepting.rawValue, forKey: "r") + case let .accepted(key, keyFingerprint): + encoder.encodeInt32(SecretChatRekeySessionDataValue.accepted.rawValue, forKey: "r") + encoder.encodeBytes(key, forKey: "k") + encoder.encodeInt64(keyFingerprint, forKey: "f") + } + } + + public static func ==(lhs: SecretChatRekeySessionData, rhs: SecretChatRekeySessionData) -> Bool { + switch lhs { + case .requesting: + if case .requesting = rhs { + return true + } else { + return false + } + case let .requested(a, _): + if case .requested(a, _) = rhs { + return true + } else { + return false + } + case .accepting: + if case .accepting = rhs { + return true + } else { + return false + } + case let .accepted(key, keyFingerprint): + if case .accepted(key, keyFingerprint) = rhs { + return true + } else { + return false + } + } + } +} + +public struct SecretChatRekeySessionState: PostboxCoding, Equatable { + let id: Int64 + let data: SecretChatRekeySessionData + + public init(id: Int64, data: SecretChatRekeySessionData) { + self.id = id + self.data = data + } + + public init(decoder: PostboxDecoder) { + self.id = decoder.decodeInt64ForKey("i", orElse: 0) + self.data = decoder.decodeObjectForKey("d", decoder: { SecretChatRekeySessionData(decoder: $0) }) as! SecretChatRekeySessionData + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id, forKey: "i") + encoder.encodeObject(self.data, forKey: "d") + } + + public static func ==(lhs: SecretChatRekeySessionState, rhs: SecretChatRekeySessionState) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.data != rhs.data { + return false + } + return true + } +} + +public struct SecretChatSequenceBasedLayerState: PostboxCoding, Equatable { + let layerNegotiationState: SecretChatLayerNegotiationState + let rekeyState: SecretChatRekeySessionState? + public let baseIncomingOperationIndex: Int32 + public let baseOutgoingOperationIndex: Int32 + let topProcessedCanonicalIncomingOperationIndex: Int32? + + public init(layerNegotiationState: SecretChatLayerNegotiationState, rekeyState: SecretChatRekeySessionState?, baseIncomingOperationIndex: Int32, baseOutgoingOperationIndex: Int32, topProcessedCanonicalIncomingOperationIndex: Int32?) { + self.layerNegotiationState = layerNegotiationState + self.rekeyState = rekeyState + self.baseIncomingOperationIndex = baseIncomingOperationIndex + self.baseOutgoingOperationIndex = baseOutgoingOperationIndex + self.topProcessedCanonicalIncomingOperationIndex = topProcessedCanonicalIncomingOperationIndex + } + + public init(decoder: PostboxDecoder) { + self.layerNegotiationState = decoder.decodeObjectForKey("ln", decoder: { SecretChatLayerNegotiationState(decoder: $0) }) as! SecretChatLayerNegotiationState + self.rekeyState = decoder.decodeObjectForKey("rs", decoder: { SecretChatRekeySessionState(decoder: $0) }) as? SecretChatRekeySessionState + self.baseIncomingOperationIndex = decoder.decodeInt32ForKey("bi", orElse: 0) + self.baseOutgoingOperationIndex = decoder.decodeInt32ForKey("bo", orElse: 0) + if let topProcessedCanonicalIncomingOperationIndex = decoder.decodeOptionalInt32ForKey("pi") { + self.topProcessedCanonicalIncomingOperationIndex = topProcessedCanonicalIncomingOperationIndex + } else { + self.topProcessedCanonicalIncomingOperationIndex = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.layerNegotiationState, forKey: "ln") + if let rekeyState = self.rekeyState { + encoder.encodeObject(rekeyState, forKey: "rs") + } else { + encoder.encodeNil(forKey: "rs") + } + encoder.encodeInt32(self.baseIncomingOperationIndex, forKey: "bi") + encoder.encodeInt32(self.baseOutgoingOperationIndex, forKey: "bo") + if let topProcessedCanonicalIncomingOperationIndex = self.topProcessedCanonicalIncomingOperationIndex { + encoder.encodeInt32(topProcessedCanonicalIncomingOperationIndex, forKey: "pi") + } else { + encoder.encodeNil(forKey: "pi") + } + } + + func canonicalIncomingOperationIndex(_ index: Int32) -> Int32 { + return index - self.baseIncomingOperationIndex + } + + func canonicalOutgoingOperationIndex(_ index: Int32) -> Int32 { + return index - self.baseOutgoingOperationIndex + } + + func outgoingOperationIndexFromCanonicalOperationIndex(_ index: Int32) -> Int32 { + return index + self.baseOutgoingOperationIndex + } + + func withUpdatedLayerNegotiationState(_ layerNegotiationState: SecretChatLayerNegotiationState) -> SecretChatSequenceBasedLayerState { + return SecretChatSequenceBasedLayerState(layerNegotiationState: layerNegotiationState, rekeyState: self.rekeyState, baseIncomingOperationIndex: self.baseIncomingOperationIndex, baseOutgoingOperationIndex: self.baseOutgoingOperationIndex, topProcessedCanonicalIncomingOperationIndex: self.topProcessedCanonicalIncomingOperationIndex) + } + + func withUpdatedRekeyState(_ rekeyState: SecretChatRekeySessionState?) -> SecretChatSequenceBasedLayerState { + return SecretChatSequenceBasedLayerState(layerNegotiationState: self.layerNegotiationState, rekeyState: rekeyState, baseIncomingOperationIndex: self.baseIncomingOperationIndex, baseOutgoingOperationIndex: self.baseOutgoingOperationIndex, topProcessedCanonicalIncomingOperationIndex: self.topProcessedCanonicalIncomingOperationIndex) + } + + func withUpdatedTopProcessedCanonicalIncomingOperationIndex(_ topProcessedCanonicalIncomingOperationIndex: Int32?) -> SecretChatSequenceBasedLayerState { + return SecretChatSequenceBasedLayerState(layerNegotiationState: self.layerNegotiationState, rekeyState: self.rekeyState, baseIncomingOperationIndex: self.baseIncomingOperationIndex, baseOutgoingOperationIndex: self.baseOutgoingOperationIndex, topProcessedCanonicalIncomingOperationIndex: topProcessedCanonicalIncomingOperationIndex) + } + + public static func ==(lhs: SecretChatSequenceBasedLayerState, rhs: SecretChatSequenceBasedLayerState) -> Bool { + if lhs.layerNegotiationState != rhs.layerNegotiationState { + return false + } + if lhs.rekeyState != rhs.rekeyState { + return false + } + if lhs.baseIncomingOperationIndex != rhs.baseIncomingOperationIndex || lhs.baseOutgoingOperationIndex != rhs.baseOutgoingOperationIndex { + return false + } + if lhs.topProcessedCanonicalIncomingOperationIndex != rhs.topProcessedCanonicalIncomingOperationIndex { + return false + } + return true + } +} + +public enum SecretChatEmbeddedState: PostboxCoding, Equatable { + case terminated + case handshake(SecretChatHandshakeState) + case basicLayer + case sequenceBasedLayer(SecretChatSequenceBasedLayerState) + + public var peerState: SecretChatEmbeddedPeerState { + switch self { + case .terminated: + return .terminated + case .handshake: + return .handshake + case .basicLayer, .sequenceBasedLayer: + return .active + } + } + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SecretChatEmbeddedStateValue.terminated.rawValue: + self = .terminated + case SecretChatEmbeddedStateValue.handshake.rawValue: + self = .handshake(decoder.decodeObjectForKey("s", decoder: { SecretChatHandshakeState(decoder: $0) }) as! SecretChatHandshakeState) + case SecretChatEmbeddedStateValue.basicLayer.rawValue: + self = .basicLayer + case SecretChatEmbeddedStateValue.sequenceBasedLayer.rawValue: + self = .sequenceBasedLayer(decoder.decodeObjectForKey("s", decoder: { SecretChatSequenceBasedLayerState(decoder: $0) }) as! SecretChatSequenceBasedLayerState) + default: + assertionFailure() + self = .terminated + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .terminated: + encoder.encodeInt32(SecretChatEmbeddedStateValue.terminated.rawValue, forKey: "r") + case let .handshake(state): + encoder.encodeInt32(SecretChatEmbeddedStateValue.handshake.rawValue, forKey: "r") + encoder.encodeObject(state, forKey: "s") + case .basicLayer: + encoder.encodeInt32(SecretChatEmbeddedStateValue.basicLayer.rawValue, forKey: "r") + case let .sequenceBasedLayer(state): + encoder.encodeInt32(SecretChatEmbeddedStateValue.sequenceBasedLayer.rawValue, forKey: "r") + encoder.encodeObject(state, forKey: "s") + } + } + + public static func ==(lhs: SecretChatEmbeddedState, rhs: SecretChatEmbeddedState) -> Bool { + switch lhs { + case .terminated: + if case .terminated = rhs { + return true + } else { + return false + } + case let .handshake(state): + if case .handshake(state) = rhs { + return true + } else { + return false + } + case .basicLayer: + if case .basicLayer = rhs { + return true + } else { + return false + } + case let .sequenceBasedLayer(state): + if case .sequenceBasedLayer(state) = rhs { + return true + } else { + return false + } + } + } +} + +public protocol SecretChatKeyState { + var keyFingerprint: SecretChatKeyFingerprint? { get } +} + +public final class SecretChatState: PeerChatState, SecretChatKeyState, Equatable { + let role: SecretChatRole + public let embeddedState: SecretChatEmbeddedState + let keychain: SecretChatKeychain + public let keyFingerprint: SecretChatKeyFingerprint? + let messageAutoremoveTimeout: Int32? + + public init(role: SecretChatRole, embeddedState: SecretChatEmbeddedState, keychain: SecretChatKeychain, keyFingerprint: SecretChatKeyFingerprint?, messageAutoremoveTimeout: Int32?) { + self.role = role + self.embeddedState = embeddedState + self.keychain = keychain + self.keyFingerprint = keyFingerprint + self.messageAutoremoveTimeout = messageAutoremoveTimeout + } + + public init(decoder: PostboxDecoder) { + self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("r", orElse: 0))! + self.embeddedState = decoder.decodeObjectForKey("s", decoder: { return SecretChatEmbeddedState(decoder: $0) }) as! SecretChatEmbeddedState + self.keychain = decoder.decodeObjectForKey("k", decoder: { return SecretChatKeychain(decoder: $0) }) as! SecretChatKeychain + self.keyFingerprint = decoder.decodeObjectForKey("f", decoder: { return SecretChatKeyFingerprint(decoder: $0) }) as? SecretChatKeyFingerprint + self.messageAutoremoveTimeout = decoder.decodeOptionalInt32ForKey("a") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.role.rawValue, forKey: "r") + encoder.encodeObject(self.embeddedState, forKey: "s") + encoder.encodeObject(self.keychain, forKey: "k") + if let keyFingerprint = self.keyFingerprint { + encoder.encodeObject(keyFingerprint, forKey: "f") + } else { + encoder.encodeNil(forKey: "f") + } + if let messageAutoremoveTimeout = self.messageAutoremoveTimeout { + encoder.encodeInt32(messageAutoremoveTimeout, forKey: "a") + } else { + encoder.encodeNil(forKey: "a") + } + } + + public func equals(_ other: PeerChatState) -> Bool { + if let other = other as? SecretChatState, other == self { + return true + } + return false + } + + public static func ==(lhs: SecretChatState, rhs: SecretChatState) -> Bool { + return lhs.role == rhs.role && lhs.embeddedState == rhs.embeddedState && lhs.keychain == rhs.keychain && lhs.messageAutoremoveTimeout == rhs.messageAutoremoveTimeout + } + + func withUpdatedKeyFingerprint(_ keyFingerprint: SecretChatKeyFingerprint?) -> SecretChatState { + return SecretChatState(role: self.role, embeddedState: self.embeddedState, keychain: self.keychain, keyFingerprint: keyFingerprint, messageAutoremoveTimeout: self.messageAutoremoveTimeout) + } + + func withUpdatedEmbeddedState(_ embeddedState: SecretChatEmbeddedState) -> SecretChatState { + return SecretChatState(role: self.role, embeddedState: embeddedState, keychain: self.keychain, keyFingerprint: self.keyFingerprint, messageAutoremoveTimeout: self.messageAutoremoveTimeout) + } + + func withUpdatedKeychain(_ keychain: SecretChatKeychain) -> SecretChatState { + return SecretChatState(role: self.role, embeddedState: self.embeddedState, keychain: keychain, keyFingerprint: self.keyFingerprint, messageAutoremoveTimeout: self.messageAutoremoveTimeout) + } + + func withUpdatedMessageAutoremoveTimeout(_ messageAutoremoveTimeout: Int32?) -> SecretChatState { + return SecretChatState(role: self.role, embeddedState: self.embeddedState, keychain: self.keychain, keyFingerprint: self.keyFingerprint, messageAutoremoveTimeout: messageAutoremoveTimeout) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureFileMediaResource.swift b/submodules/TelegramCore/TelegramCore/SecureFileMediaResource.swift new file mode 100644 index 0000000000..8e11506721 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureFileMediaResource.swift @@ -0,0 +1,83 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct SecureFileMediaResourceId: MediaResourceId { + let fileId: Int64 + + init(fileId: Int64) { + self.fileId = fileId + } + + public var uniqueId: String { + return "telegram-secure-file-\(self.fileId)" + } + + public var hashValue: Int { + return self.fileId.hashValue + } + + public func isEqual(to: MediaResourceId) -> Bool { + if let to = to as? SecureFileMediaResourceId { + return self.fileId == to.fileId + } else { + return false + } + } +} + +public class SecureFileMediaResource: TelegramCloudMediaResource, TelegramMultipartFetchableResource, EncryptedMediaResource { + public let file: SecureIdFileReference + + public var id: MediaResourceId { + return SecureFileMediaResourceId(fileId: self.file.id) + } + + public var datacenterId: Int { + return Int(self.file.datacenterId) + } + + public var size: Int? { + return Int(self.file.size) + } + + func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? { + return Api.InputFileLocation.inputSecureFileLocation(id: self.file.id, accessHash: self.file.accessHash) + } + + public init(file: SecureIdFileReference) { + self.file = file + } + + public required init(decoder: PostboxDecoder) { + self.file = SecureIdFileReference(id: decoder.decodeInt64ForKey("f", orElse: 0), accessHash: decoder.decodeInt64ForKey("a", orElse: 0), size: decoder.decodeInt32ForKey("n", orElse: 0), datacenterId: decoder.decodeInt32ForKey("d", orElse: 0), timestamp: decoder.decodeInt32ForKey("t", orElse: 0), fileHash: decoder.decodeBytesForKey("h")?.makeData() ?? Data(), encryptedSecret: decoder.decodeBytesForKey("s")?.makeData() ?? Data()) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.file.id, forKey: "f") + encoder.encodeInt64(self.file.accessHash, forKey: "a") + encoder.encodeInt32(self.file.size, forKey: "n") + encoder.encodeInt32(self.file.datacenterId, forKey: "d") + encoder.encodeInt32(self.file.timestamp, forKey: "t") + encoder.encodeBytes(MemoryBuffer(data: self.file.fileHash), forKey: "h") + encoder.encodeBytes(MemoryBuffer(data: self.file.encryptedSecret), forKey: "s") + } + + public func isEqual(to: MediaResource) -> Bool { + if let to = to as? SecureFileMediaResource { + return self.file == to.file + } else { + return false + } + } + + public func decrypt(data: Data, params: Any) -> Data? { + guard let context = params as? SecureIdAccessContext else { + return nil + } + return decryptedSecureIdFile(context: context, encryptedData: data, fileHash: self.file.fileHash, encryptedSecret: self.file.encryptedSecret) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdAddressValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdAddressValue.swift new file mode 100644 index 0000000000..59d5890b7d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdAddressValue.swift @@ -0,0 +1,78 @@ +import Foundation + +public struct SecureIdAddressValue: Equatable { + public var street1: String + public var street2: String + public var city: String + public var state: String + public var countryCode: String + public var postcode: String + + public init(street1: String, street2: String, city: String, state: String, countryCode: String, postcode: String) { + self.street1 = street1 + self.street2 = street2 + self.city = city + self.state = state + self.countryCode = countryCode + self.postcode = postcode + } + + public static func ==(lhs: SecureIdAddressValue, rhs: SecureIdAddressValue) -> Bool { + if lhs.street1 != rhs.street1 { + return false + } + if lhs.street2 != rhs.street2 { + return false + } + if lhs.city != rhs.city { + return false + } + if lhs.state != rhs.state { + return false + } + if lhs.countryCode != rhs.countryCode { + return false + } + if lhs.postcode != rhs.postcode { + return false + } + return true + } +} + +extension SecureIdAddressValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference]) { + guard let street1 = dict["street_line1"] as? String else { + return nil + } + let street2 = (dict["street_line2"] as? String) ?? "" + guard let city = dict["city"] as? String else { + return nil + } + guard let state = dict["state"] as? String else { + return nil + } + guard let countryCode = dict["country_code"] as? String else { + return nil + } + guard let postcode = dict["post_code"] as? String else { + return nil + } + + self.init(street1: street1, street2: street2, city: city, state: state, countryCode: countryCode, postcode: postcode) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference]) { + var dict: [String: Any] = [:] + dict["street_line1"] = self.street1 + if !self.street2.isEmpty { + dict["street_line2"] = self.street2 + } + dict["city"] = self.city + dict["state"] = self.state + dict["country_code"] = self.countryCode + dict["post_code"] = self.postcode + + return (dict, []) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdBankStatementValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdBankStatementValue.swift new file mode 100644 index 0000000000..f0fd226a4d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdBankStatementValue.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct SecureIdBankStatementValue: Equatable { + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + + public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + self.verificationDocuments = verificationDocuments + self.translations = translations + } + + public static func ==(lhs: SecureIdBankStatementValue, rhs: SecureIdBankStatementValue) -> Bool { + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + return true + } +} + +extension SecureIdBankStatementValue { + init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(verificationDocuments: verificationDocuments, translations: translations) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { + return ([:], self.verificationDocuments, self.translations) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdConfiguration.swift b/submodules/TelegramCore/TelegramCore/SecureIdConfiguration.swift new file mode 100644 index 0000000000..7782a24598 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdConfiguration.swift @@ -0,0 +1,89 @@ +import Foundation +#if os(macOS) +import PostboxMac +import MtProtoKitMac +import SwiftSignalKitMac +#else +import Postbox +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +import SwiftSignalKit +#endif + +final class CachedSecureIdConfiguration: PostboxCoding { + let value: SecureIdConfiguration + let hash: Int32 + + init(value: SecureIdConfiguration, hash: Int32) { + self.value = value + self.hash = hash + } + + init(decoder: PostboxDecoder) { + self.value = decoder.decodeObjectForKey("value", decoder: { SecureIdConfiguration(decoder: $0) }) as! SecureIdConfiguration + self.hash = decoder.decodeInt32ForKey("hash", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.value, forKey: "value") + encoder.encodeInt32(self.hash, forKey: "hash") + } +} + +public struct SecureIdConfiguration: PostboxCoding { + public let nativeLanguageByCountry: [String: String] + + fileprivate init(jsonString: String) { + self.nativeLanguageByCountry = (try? JSONDecoder().decode(Dictionary.self, from: jsonString.data(using: .utf8) ?? Data())) ?? [:] + } + + public init(decoder: PostboxDecoder) { + let nativeLanguageByCountryData = decoder.decodeBytesForKey("nativeLanguageByCountry")! + self.nativeLanguageByCountry = (try? JSONDecoder().decode(Dictionary.self, from: nativeLanguageByCountryData.dataNoCopy())) ?? [:] + } + + public func encode(_ encoder: PostboxEncoder) { + let nativeLanguageByCountryData = (try? JSONEncoder().encode(self.nativeLanguageByCountry)) ?? Data() + encoder.encodeBytes(MemoryBuffer(data: nativeLanguageByCountryData), forKey: "nativeLanguageByCountry") + } +} + +public func secureIdConfiguration(postbox: Postbox, network: Network) -> Signal { + let cached: Signal = postbox.transaction { transaction -> CachedSecureIdConfiguration? in + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0))) as? CachedSecureIdConfiguration { + return entry + } else { + return nil + } + } + return cached + |> mapToSignal { cached -> Signal in + return network.request(Api.functions.help.getPassportConfig(hash: cached?.hash ?? 0)) + |> retryRequest + |> mapToSignal { result -> Signal in + let parsed: CachedSecureIdConfiguration + switch result { + case .passportConfigNotModified: + if let cached = cached { + return .single(cached.value) + } else { + assertionFailure() + return .complete() + } + case let .passportConfig(hash, countriesLangs): + switch countriesLangs { + case let .dataJSON(data): + let value = SecureIdConfiguration(jsonString: data) + parsed = CachedSecureIdConfiguration(value: value, hash: hash) + } + } + return postbox.transaction { transaction -> SecureIdConfiguration in + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)), entry: parsed, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + return parsed.value + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdDataTypes.swift b/submodules/TelegramCore/TelegramCore/SecureIdDataTypes.swift new file mode 100644 index 0000000000..344e5db28b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdDataTypes.swift @@ -0,0 +1,94 @@ +import Foundation + +public struct SecureIdPersonName: Equatable { + public let firstName: String + public let lastName: String + public let middleName: String + + public init(firstName: String, lastName: String, middleName: String) { + self.firstName = firstName + self.lastName = lastName + self.middleName = middleName + } + + public func isComplete() -> Bool { + return !self.firstName.isEmpty && !self.lastName.isEmpty + } +} + +public struct SecureIdDate: Equatable { + public let day: Int32 + public let month: Int32 + public let year: Int32 + + public init(day: Int32, month: Int32, year: Int32) { + self.day = day + self.month = month + self.year = year + } +} + +public enum SecureIdGender { + case male + case female +} + +public struct SecureIdFileReference: Equatable { + public let id: Int64 + let accessHash: Int64 + let size: Int32 + let datacenterId: Int32 + public let timestamp: Int32 + public let fileHash: Data + let encryptedSecret: Data +} + +extension SecureIdFileReference { + init?(apiFile: Api.SecureFile) { + switch apiFile { + case let .secureFile(id, accessHash, size, dcId, date, fileHash, secret): + self.init(id: id, accessHash: accessHash, size: size, datacenterId: dcId, timestamp: date, fileHash: fileHash.makeData(), encryptedSecret: secret.makeData()) + case .secureFileEmpty: + return nil + } + } +} + +extension SecureIdGender { + init?(serializedString: String) { + switch serializedString { + case "male": + self = .male + case "female": + self = .female + default: + return nil + } + } + + func serialize() -> String { + switch self { + case .male: + return "male" + case .female: + return "female" + } + } +} + +extension SecureIdDate { + init?(serializedString: String) { + let data = serializedString.components(separatedBy: ".") + guard data.count == 3 else { + return nil + } + guard let day = Int32(data[0]), let month = Int32(data[1]), let year = Int32(data[2]) else { + return nil + } + self.init(day: day, month: month, year: year) + } + + func serialize() -> String { + return "\(self.day < 10 ? "0\(self.day)" : "\(self.day)").\(self.month < 10 ? "0\(self.month)" : "\(self.month)").\(self.year)" + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdDriversLicenseValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdDriversLicenseValue.swift new file mode 100644 index 0000000000..5d98ed7048 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdDriversLicenseValue.swift @@ -0,0 +1,69 @@ +import Foundation + +public struct SecureIdDriversLicenseValue: Equatable { + public var identifier: String + public var expiryDate: SecureIdDate? + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + public var selfieDocument: SecureIdVerificationDocumentReference? + public var frontSideDocument: SecureIdVerificationDocumentReference? + public var backSideDocument: SecureIdVerificationDocumentReference? + + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + self.identifier = identifier + self.expiryDate = expiryDate + self.verificationDocuments = verificationDocuments + self.translations = translations + self.selfieDocument = selfieDocument + self.frontSideDocument = frontSideDocument + self.backSideDocument = backSideDocument + } + + public static func ==(lhs: SecureIdDriversLicenseValue, rhs: SecureIdDriversLicenseValue) -> Bool { + if lhs.identifier != rhs.identifier { + return false + } + if lhs.expiryDate != rhs.expiryDate { + return false + } + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + if lhs.selfieDocument != rhs.selfieDocument { + return false + } + if lhs.frontSideDocument != rhs.frontSideDocument { + return false + } + if lhs.backSideDocument != rhs.backSideDocument { + return false + } + return true + } +} + +extension SecureIdDriversLicenseValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + guard let identifier = dict["document_no"] as? String else { + return nil + } + let expiryDate = (dict["expiry_date"] as? String).flatMap(SecureIdDate.init) + + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + var dict: [String: Any] = [:] + dict["document_no"] = self.identifier + if let expiryDate = self.expiryDate { + dict["expiry_date"] = expiryDate.serialize() + } + + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument, self.backSideDocument) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdEmailValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdEmailValue.swift new file mode 100644 index 0000000000..021a1b8fad --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdEmailValue.swift @@ -0,0 +1,16 @@ +import Foundation + +public struct SecureIdEmailValue: Equatable { + public let email: String + + public init(email: String) { + self.email = email + } + + public static func ==(lhs: SecureIdEmailValue, rhs: SecureIdEmailValue) -> Bool { + if lhs.email != rhs.email { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdForm.swift b/submodules/TelegramCore/TelegramCore/SecureIdForm.swift new file mode 100644 index 0000000000..fa122c6969 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdForm.swift @@ -0,0 +1,52 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum SecureIdRequestedFormField: Equatable { + case just(SecureIdRequestedFormFieldValue) + case oneOf([SecureIdRequestedFormFieldValue]) +} + +public enum SecureIdRequestedFormFieldValue: Equatable { + case personalDetails(nativeName: Bool) + case passport(selfie: Bool, translation: Bool) + case driversLicense(selfie: Bool, translation: Bool) + case idCard(selfie: Bool, translation: Bool) + case internalPassport(selfie: Bool, translation: Bool) + case passportRegistration(translation: Bool) + case address + case utilityBill(translation: Bool) + case bankStatement(translation: Bool) + case rentalAgreement(translation: Bool) + case phone + case email + case temporaryRegistration(translation: Bool) +} + +public struct SecureIdForm: Equatable { + public let peerId: PeerId + public let requestedFields: [SecureIdRequestedFormField] + public let values: [SecureIdValueWithContext] + + public init(peerId: PeerId, requestedFields: [SecureIdRequestedFormField], values: [SecureIdValueWithContext]) { + self.peerId = peerId + self.requestedFields = requestedFields + self.values = values + } + + public static func ==(lhs: SecureIdForm, rhs: SecureIdForm) -> Bool { + if lhs.peerId != rhs.peerId { + return false + } + if lhs.requestedFields != rhs.requestedFields { + return false + } + if lhs.values != rhs.values { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdIDCardValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdIDCardValue.swift new file mode 100644 index 0000000000..f2d3d8eeba --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdIDCardValue.swift @@ -0,0 +1,69 @@ +import Foundation + +public struct SecureIdIDCardValue: Equatable { + public var identifier: String + public var expiryDate: SecureIdDate? + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + public var selfieDocument: SecureIdVerificationDocumentReference? + public var frontSideDocument: SecureIdVerificationDocumentReference? + public var backSideDocument: SecureIdVerificationDocumentReference? + + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + self.identifier = identifier + self.expiryDate = expiryDate + self.verificationDocuments = verificationDocuments + self.translations = translations + self.selfieDocument = selfieDocument + self.frontSideDocument = frontSideDocument + self.backSideDocument = backSideDocument + } + + public static func ==(lhs: SecureIdIDCardValue, rhs: SecureIdIDCardValue) -> Bool { + if lhs.identifier != rhs.identifier { + return false + } + if lhs.expiryDate != rhs.expiryDate { + return false + } + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + if lhs.selfieDocument != rhs.selfieDocument { + return false + } + if lhs.frontSideDocument != rhs.frontSideDocument { + return false + } + if lhs.backSideDocument != rhs.backSideDocument { + return false + } + return true + } +} + +extension SecureIdIDCardValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + guard let identifier = dict["document_no"] as? String else { + return nil + } + let expiryDate = (dict["expiry_date"] as? String).flatMap(SecureIdDate.init) + + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + var dict: [String: Any] = [:] + dict["document_no"] = self.identifier + if let expiryDate = self.expiryDate { + dict["expiry_date"] = expiryDate.serialize() + } + + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument, self.backSideDocument) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdInternalPassportValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdInternalPassportValue.swift new file mode 100644 index 0000000000..fa0cb61ae7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdInternalPassportValue.swift @@ -0,0 +1,64 @@ +import Foundation + +public struct SecureIdInternalPassportValue: Equatable { + public var identifier: String + public var expiryDate: SecureIdDate? + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + public var selfieDocument: SecureIdVerificationDocumentReference? + public var frontSideDocument: SecureIdVerificationDocumentReference? + + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + self.identifier = identifier + self.expiryDate = expiryDate + self.verificationDocuments = verificationDocuments + self.translations = translations + self.selfieDocument = selfieDocument + self.frontSideDocument = frontSideDocument + } + + public static func ==(lhs: SecureIdInternalPassportValue, rhs: SecureIdInternalPassportValue) -> Bool { + if lhs.identifier != rhs.identifier { + return false + } + if lhs.expiryDate != rhs.expiryDate { + return false + } + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + if lhs.selfieDocument != rhs.selfieDocument { + return false + } + if lhs.frontSideDocument != rhs.frontSideDocument { + return false + } + return true + } +} + +extension SecureIdInternalPassportValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + guard let identifier = dict["document_no"] as? String else { + return nil + } + let expiryDate = (dict["expiry_date"] as? String).flatMap(SecureIdDate.init) + + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + var dict: [String: Any] = [:] + dict["document_no"] = self.identifier + if let expiryDate = self.expiryDate { + dict["expiry_date"] = expiryDate.serialize() + } + + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdPadding.swift b/submodules/TelegramCore/TelegramCore/SecureIdPadding.swift new file mode 100644 index 0000000000..9d738ff468 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdPadding.swift @@ -0,0 +1,26 @@ +import Foundation + +func paddedSecureIdData(_ data: Data) -> Data { + var paddingCount = Int(47 + arc4random_uniform(255 - 47)) + paddingCount -= ((data.count + paddingCount) % 16) + var result = Data(count: paddingCount + data.count) + result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + bytes.advanced(by: 0).pointee = UInt8(paddingCount) + arc4random_buf(bytes.advanced(by: 1), paddingCount - 1) + data.withUnsafeBytes { (source: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: paddingCount), source, data.count) + } + } + return result +} + +func unpaddedSecureIdData(_ data: Data) -> Data? { + var paddingCount: UInt8 = 0 + data.copyBytes(to: &paddingCount, count: 1) + + if paddingCount < 0 || paddingCount > data.count { + return nil + } + + return data.subdata(in: Int(paddingCount) ..< data.count) +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdPassportRegistrationValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdPassportRegistrationValue.swift new file mode 100644 index 0000000000..6cc697881e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdPassportRegistrationValue.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct SecureIdPassportRegistrationValue: Equatable { + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + + public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + self.verificationDocuments = verificationDocuments + self.translations = translations + } + + public static func ==(lhs: SecureIdPassportRegistrationValue, rhs: SecureIdPassportRegistrationValue) -> Bool { + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + return true + } +} + +extension SecureIdPassportRegistrationValue { + init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(verificationDocuments: verificationDocuments, translations: translations) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { + return ([:], self.verificationDocuments, self.translations) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdPassportValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdPassportValue.swift new file mode 100644 index 0000000000..4c8af48014 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdPassportValue.swift @@ -0,0 +1,65 @@ +import Foundation + +public struct SecureIdPassportValue: Equatable { + public var identifier: String + public var expiryDate: SecureIdDate? + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + public var selfieDocument: SecureIdVerificationDocumentReference? + public var frontSideDocument: SecureIdVerificationDocumentReference? + + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + self.identifier = identifier + self.expiryDate = expiryDate + self.verificationDocuments = verificationDocuments + self.translations = translations + self.selfieDocument = selfieDocument + self.frontSideDocument = frontSideDocument + } + + public static func ==(lhs: SecureIdPassportValue, rhs: SecureIdPassportValue) -> Bool { + if lhs.identifier != rhs.identifier { + return false + } + if lhs.expiryDate != rhs.expiryDate { + return false + } + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + if lhs.selfieDocument != rhs.selfieDocument { + return false + } + if lhs.frontSideDocument != rhs.frontSideDocument { + return false + } + return true + } +} + +extension SecureIdPassportValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + guard let identifier = dict["document_no"] as? String else { + return nil + } + let expiryDate = (dict["expiry_date"] as? String).flatMap(SecureIdDate.init) + + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + var dict: [String: Any] = [:] + dict["document_no"] = self.identifier + if let expiryDate = self.expiryDate { + dict["expiry_date"] = expiryDate.serialize() + } + + return (dict, self.verificationDocuments, + self.translations, self.selfieDocument, self.frontSideDocument) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdPersonalDetailsValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdPersonalDetailsValue.swift new file mode 100644 index 0000000000..895814497b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdPersonalDetailsValue.swift @@ -0,0 +1,73 @@ +import Foundation + +public struct SecureIdPersonalDetailsValue: Equatable { + public var latinName: SecureIdPersonName + public var nativeName: SecureIdPersonName? + public var birthdate: SecureIdDate + public var countryCode: String + public var residenceCountryCode: String + public var gender: SecureIdGender + + public init(latinName: SecureIdPersonName, nativeName: SecureIdPersonName?, birthdate: SecureIdDate, countryCode: String, residenceCountryCode: String, gender: SecureIdGender) { + self.latinName = latinName + self.nativeName = nativeName + self.birthdate = birthdate + self.countryCode = countryCode + self.residenceCountryCode = residenceCountryCode + self.gender = gender + } +} + +extension SecureIdPersonalDetailsValue { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference]) { + guard let firstName = dict["first_name"] as? String else { + return nil + } + guard let lastName = dict["last_name"] as? String else { + return nil + } + let middleName = dict["middle_name"] as? String ?? "" + + var nativeName: SecureIdPersonName? + if let nativeFirstName = dict["first_name_native"] as? String, let nativeLastName = dict["last_name_native"] as? String { + nativeName = SecureIdPersonName(firstName: nativeFirstName, lastName: nativeLastName, middleName: dict["middle_name_native"] as? String ?? "") + } + + guard let birthdate = (dict["birth_date"] as? String).flatMap(SecureIdDate.init) else { + return nil + } + guard let gender = (dict["gender"] as? String).flatMap(SecureIdGender.init) else { + return nil + } + guard let countryCode = dict["country_code"] as? String else { + return nil + } + guard let residenceCountryCode = dict["residence_country_code"] as? String else { + return nil + } + + self.init(latinName: SecureIdPersonName(firstName: firstName, lastName: lastName, middleName: middleName), nativeName: nativeName, birthdate: birthdate, countryCode: countryCode, residenceCountryCode: residenceCountryCode, gender: gender) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference]) { + var dict: [String: Any] = [:] + dict["first_name"] = self.latinName.firstName + if !self.latinName.middleName.isEmpty { + dict["middle_name"] = self.latinName.middleName + } + dict["last_name"] = self.latinName.lastName + if let nativeName = self.nativeName { + dict["first_name_native"] = nativeName.firstName + if !nativeName.middleName.isEmpty { + dict["middle_name_native"] = nativeName.middleName + } + dict["last_name_native"] = nativeName.lastName + } + dict["birth_date"] = self.birthdate.serialize() + dict["gender"] = self.gender.serialize() + dict["country_code"] = self.countryCode + dict["residence_country_code"] = self.residenceCountryCode + + return (dict, []) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdPhoneValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdPhoneValue.swift new file mode 100644 index 0000000000..e45f4fa631 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdPhoneValue.swift @@ -0,0 +1,16 @@ +import Foundation + +public struct SecureIdPhoneValue: Equatable { + public let phone: String + + public init(phone: String) { + self.phone = phone + } + + public static func ==(lhs: SecureIdPhoneValue, rhs: SecureIdPhoneValue) -> Bool { + if lhs.phone != rhs.phone { + return false + } + return true + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdRentalAgreementValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdRentalAgreementValue.swift new file mode 100644 index 0000000000..2d45369970 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdRentalAgreementValue.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct SecureIdRentalAgreementValue: Equatable { + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + + public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + self.verificationDocuments = verificationDocuments + self.translations = translations + } + + public static func ==(lhs: SecureIdRentalAgreementValue, rhs: SecureIdRentalAgreementValue) -> Bool { + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + return true + } +} + +extension SecureIdRentalAgreementValue { + init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(verificationDocuments: verificationDocuments, translations: translations) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { + return ([:], self.verificationDocuments, self.translations) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdTemporaryRegistrationValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdTemporaryRegistrationValue.swift new file mode 100644 index 0000000000..6b6e8755bd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdTemporaryRegistrationValue.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct SecureIdTemporaryRegistrationValue: Equatable { + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + + public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + self.verificationDocuments = verificationDocuments + self.translations = translations + } + + public static func ==(lhs: SecureIdTemporaryRegistrationValue, rhs: SecureIdTemporaryRegistrationValue) -> Bool { + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + return true + } +} + +extension SecureIdTemporaryRegistrationValue { + init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(verificationDocuments: verificationDocuments, translations: translations) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { + return ([:], self.verificationDocuments, self.translations) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdUtilityBillValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdUtilityBillValue.swift new file mode 100644 index 0000000000..72a845edfb --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdUtilityBillValue.swift @@ -0,0 +1,33 @@ +import Foundation + +public struct SecureIdUtilityBillValue: Equatable { + public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] + + public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + self.verificationDocuments = verificationDocuments + self.translations = translations + } + + public static func ==(lhs: SecureIdUtilityBillValue, rhs: SecureIdUtilityBillValue) -> Bool { + if lhs.verificationDocuments != rhs.verificationDocuments { + return false + } + if lhs.translations != rhs.translations { + return false + } + return true + } +} + +extension SecureIdUtilityBillValue { + init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { + let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences + + self.init(verificationDocuments: verificationDocuments, translations: translations) + } + + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { + return ([:], self.verificationDocuments, self.translations) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdValue.swift b/submodules/TelegramCore/TelegramCore/SecureIdValue.swift new file mode 100644 index 0000000000..41d8e8bad6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdValue.swift @@ -0,0 +1,208 @@ +import Foundation + +public enum SecureIdValueKey: Int32 { + case personalDetails + case passport + case internalPassport + case driversLicense + case idCard + case address + case utilityBill + case bankStatement + case rentalAgreement + case passportRegistration + case temporaryRegistration + case phone + case email +} + +public enum SecureIdValue: Equatable { + case personalDetails(SecureIdPersonalDetailsValue) + case passport(SecureIdPassportValue) + case internalPassport(SecureIdInternalPassportValue) + case driversLicense(SecureIdDriversLicenseValue) + case idCard(SecureIdIDCardValue) + case address(SecureIdAddressValue) + case passportRegistration(SecureIdPassportRegistrationValue) + case temporaryRegistration(SecureIdTemporaryRegistrationValue) + case utilityBill(SecureIdUtilityBillValue) + case bankStatement(SecureIdBankStatementValue) + case rentalAgreement(SecureIdRentalAgreementValue) + case phone(SecureIdPhoneValue) + case email(SecureIdEmailValue) + + var fileReferences: [SecureIdVerificationDocumentReference] { + switch self { + case let .passport(passport): + var result = passport.verificationDocuments + if let selfie = passport.selfieDocument { + result.append(selfie) + } + if let frontSide = passport.frontSideDocument { + result.append(frontSide) + } + result.append(contentsOf: passport.translations) + return result + case let .internalPassport(passport): + var result = passport.verificationDocuments + if let selfie = passport.selfieDocument { + result.append(selfie) + } + if let frontSide = passport.frontSideDocument { + result.append(frontSide) + } + result.append(contentsOf: passport.translations) + return result + case let .driversLicense(driversLicense): + var result = driversLicense.verificationDocuments + if let selfie = driversLicense.selfieDocument { + result.append(selfie) + } + if let frontSide = driversLicense.frontSideDocument { + result.append(frontSide) + } + if let backSide = driversLicense.backSideDocument { + result.append(backSide) + } + result.append(contentsOf: driversLicense.translations) + return result + case let .idCard(idCard): + var result = idCard.verificationDocuments + if let selfie = idCard.selfieDocument { + result.append(selfie) + } + if let frontSide = idCard.frontSideDocument { + result.append(frontSide) + } + if let backSide = idCard.backSideDocument { + result.append(backSide) + } + result.append(contentsOf: idCard.translations) + return result + case let .passportRegistration(passportRegistration): + return passportRegistration.verificationDocuments + passportRegistration.translations + case let .temporaryRegistration(passportRegistration): + return passportRegistration.verificationDocuments + passportRegistration.translations + case let .bankStatement(bankStatement): + return bankStatement.verificationDocuments + bankStatement.translations + case let .utilityBill(utilityBill): + return utilityBill.verificationDocuments + utilityBill.translations + case let .rentalAgreement(rentalAgreement): + return rentalAgreement.verificationDocuments + rentalAgreement.translations + default: + return [] + } + } + + public var key: SecureIdValueKey { + switch self { + case .personalDetails: + return .personalDetails + case .passport: + return .passport + case .internalPassport: + return .internalPassport + case .driversLicense: + return .driversLicense + case .idCard: + return .idCard + case .address: + return .address + case .passportRegistration: + return .passportRegistration + case .temporaryRegistration: + return .temporaryRegistration + case .utilityBill: + return .utilityBill + case .bankStatement: + return .bankStatement + case .rentalAgreement: + return .rentalAgreement + case .phone: + return .phone + case .email: + return .email + } + } +} + +public struct SecureIdValueAdditionalData { + public var nativeNames: Bool = false + public var selfie: Bool = false + public var translation: Bool = false +} + +public func extractSecureIdValueAdditionalData(_ value: SecureIdValue) -> SecureIdValueAdditionalData { + var data = SecureIdValueAdditionalData() + switch value { + case let .personalDetails(value): + data.nativeNames = value.nativeName?.isComplete() ?? false + case let .passport(value): + data.selfie = value.selfieDocument != nil + data.translation = !value.translations.isEmpty + case let .internalPassport(value): + data.selfie = value.selfieDocument != nil + data.translation = !value.translations.isEmpty + case let .idCard(value): + data.selfie = value.selfieDocument != nil + data.translation = !value.translations.isEmpty + case let .driversLicense(value): + data.selfie = value.selfieDocument != nil + data.translation = !value.translations.isEmpty + case let .utilityBill(value): + data.translation = !value.translations.isEmpty + case let .rentalAgreement(value): + data.translation = !value.translations.isEmpty + case let .bankStatement(value): + data.translation = !value.translations.isEmpty + case let .temporaryRegistration(value): + data.translation = !value.translations.isEmpty + case let .passportRegistration(value): + data.translation = !value.translations.isEmpty + default: + break + } + return data +} + +public struct SecureIdEncryptedValueFileMetadata: Equatable { + let hash: Data + let secret: Data +} + +public struct SecureIdEncryptedValueMetadata: Equatable { + let valueDataHash: Data + let decryptedSecret: Data +} + +public struct SecureIdValueWithContext: Equatable { + public let value: SecureIdValue + public let errors: [SecureIdValueContentErrorKey: SecureIdValueContentError] + let files: [SecureIdEncryptedValueFileMetadata] + let translations: [SecureIdEncryptedValueFileMetadata] + let selfie: SecureIdEncryptedValueFileMetadata? + let frontSide: SecureIdEncryptedValueFileMetadata? + let backSide: SecureIdEncryptedValueFileMetadata? + let encryptedMetadata: SecureIdEncryptedValueMetadata? + let opaqueHash: Data + + init(value: SecureIdValue, errors: [SecureIdValueContentErrorKey: SecureIdValueContentError], files: [SecureIdEncryptedValueFileMetadata], translations: [SecureIdEncryptedValueFileMetadata], selfie: SecureIdEncryptedValueFileMetadata?, frontSide: SecureIdEncryptedValueFileMetadata?, backSide: SecureIdEncryptedValueFileMetadata?, encryptedMetadata: SecureIdEncryptedValueMetadata?, opaqueHash: Data) { + self.value = value + self.errors = errors + self.files = files + self.translations = translations + self.selfie = selfie + self.frontSide = frontSide + self.backSide = backSide + self.encryptedMetadata = encryptedMetadata + self.opaqueHash = opaqueHash + } + + public func withRemovedErrors(_ keys: [SecureIdValueContentErrorKey]) -> SecureIdValueWithContext { + var errors = self.errors + for key in keys { + errors.removeValue(forKey: key) + } + return SecureIdValueWithContext(value: self.value, errors: errors, files: self.files, translations: self.translations, selfie: self.selfie, frontSide: self.frontSide, backSide: self.backSide, encryptedMetadata: self.encryptedMetadata, opaqueHash: self.opaqueHash) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdValueAccessContext.swift b/submodules/TelegramCore/TelegramCore/SecureIdValueAccessContext.swift new file mode 100644 index 0000000000..9bfc8befa6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdValueAccessContext.swift @@ -0,0 +1,32 @@ +import Foundation + +public struct SecureIdValueAccessContext: Equatable { + let secret: Data + let id: Int64 + + public static func ==(lhs: SecureIdValueAccessContext, rhs: SecureIdValueAccessContext) -> Bool { + if lhs.secret != rhs.secret { + return false + } + if lhs.id != rhs.id { + return false + } + return true + } +} + +public func generateSecureIdValueEmptyAccessContext() -> SecureIdValueAccessContext? { + return SecureIdValueAccessContext(secret: Data(), id: 0) +} + +public func generateSecureIdValueAccessContext() -> SecureIdValueAccessContext? { + guard let secret = generateSecureSecretData() else { + return nil + } + let secretHashData = sha512Digest(secret) + var secretHash: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) + } + return SecureIdValueAccessContext(secret: secret, id: secretHash) +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdValueContentError.swift b/submodules/TelegramCore/TelegramCore/SecureIdValueContentError.swift new file mode 100644 index 0000000000..74b255d41f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdValueContentError.swift @@ -0,0 +1,150 @@ +import Foundation + +public enum SecureIdValueContentErrorKey: Hashable { + case value(SecureIdValueKey) + case field(SecureIdValueContentErrorField) + case file(hash: Data) + case files(hashes: Set) + case translationFile(hash: Data) + case translationFiles(hashes: Set) + case selfie(hash: Data) + case frontSide(hash: Data) + case backSide(hash: Data) +} + +public enum SecureIdValueContentErrorField: Hashable { + case personalDetails(SecureIdValueContentErrorPersonalDetailsField) + case passport(SecureIdValueContentErrorPassportField) + case internalPassport(SecureIdValueContentErrorInternalPassportField) + case driversLicense(SecureIdValueContentErrorDriversLicenseField) + case idCard(SecureIdValueContentErrorIdCardField) + case address(SecureIdValueContentErrorAddressField) +} + +public enum SecureIdValueContentErrorPersonalDetailsField: String, Hashable { + case firstName = "first_name" + case lastName = "last_name" + case middleName = "middle_name" + case firstNameNative = "first_name_native" + case lastNameNative = "last_name_native" + case middleNameNative = "middle_name_native" + case birthdate = "birth_date" + case gender = "gender" + case countryCode = "country_code" + case residenceCountryCode = "residence_country_code" +} + +public enum SecureIdValueContentErrorPassportField: String, Hashable { + case documentId = "document_no" + case expiryDate = "expiry_date" +} + +public enum SecureIdValueContentErrorInternalPassportField: String, Hashable { + case documentId = "document_no" + case expiryDate = "expiry_date" +} + +public enum SecureIdValueContentErrorDriversLicenseField: String, Hashable { + case documentId = "document_no" + case expiryDate = "expiry_date" +} + +public enum SecureIdValueContentErrorIdCardField: String, Hashable { + case documentId = "document_no" + case expiryDate = "expiry_date" +} + +public enum SecureIdValueContentErrorAddressField: String, Hashable { + case streetLine1 = "street_line1" + case streetLine2 = "street_line2" + case city = "city" + case state = "state" + case countryCode = "country_code" + case postCode = "post_code" +} + +public typealias SecureIdValueContentError = String + +func parseSecureIdValueContentErrors(dataHash: Data?, fileHashes: Set, selfieHash: Data?, frontSideHash: Data?, backSideHash: Data?, errors: [Api.SecureValueError]) -> [SecureIdValueContentErrorKey: SecureIdValueContentError] { + var result: [SecureIdValueContentErrorKey: SecureIdValueContentError] = [:] + for error in errors { + switch error { + case let .secureValueError(type, _, text): + result[.value(SecureIdValueKey(apiType: type))] = text + case let .secureValueErrorData(type, errorDataHash, field, text): + if errorDataHash.makeData() == dataHash { + switch type { + case .secureValueTypePersonalDetails: + if let parsedField = SecureIdValueContentErrorPersonalDetailsField(rawValue: field) { + result[.field(.personalDetails(parsedField))] = text + } + case .secureValueTypePassport: + if let parsedField = SecureIdValueContentErrorPassportField(rawValue: field) { + result[.field(.passport(parsedField))] = text + } + case .secureValueTypeInternalPassport: + if let parsedField = SecureIdValueContentErrorInternalPassportField(rawValue: field) { + result[.field(.internalPassport(parsedField))] = text + } + case .secureValueTypeDriverLicense: + if let parsedField = SecureIdValueContentErrorDriversLicenseField(rawValue: field) { + result[.field(.driversLicense(parsedField))] = text + } + case .secureValueTypeIdentityCard: + if let parsedField = SecureIdValueContentErrorIdCardField(rawValue: field) { + result[.field(.idCard(parsedField))] = text + } + case .secureValueTypeAddress: + if let parsedField = SecureIdValueContentErrorAddressField(rawValue: field) { + result[.field(.address(parsedField))] = text + } + default: + break + } + } + case let .secureValueErrorFile(_, fileHash, text): + if fileHashes.contains(fileHash.makeData()) { + result[.file(hash: fileHash.makeData())] = text + } + case let .secureValueErrorFiles(_, fileHash, text): + var containsAll = true + loop: for hash in fileHash { + if !fileHashes.contains(hash.makeData()) { + containsAll = false + break loop + } + } + if containsAll { + result[.files(hashes: Set(fileHash.map { $0.makeData() }))] = text + } + case let .secureValueErrorTranslationFile(_, fileHash, text): + if fileHashes.contains(fileHash.makeData()) { + result[.translationFile(hash: fileHash.makeData())] = text + } + case let .secureValueErrorTranslationFiles(_, fileHash, text): + var containsAll = true + loop: for hash in fileHash { + if !fileHashes.contains(hash.makeData()) { + containsAll = false + break loop + } + } + if containsAll { + result[.translationFiles(hashes: Set(fileHash.map { $0.makeData() }))] = text + } + case let .secureValueErrorSelfie(_, fileHash, text): + if selfieHash == fileHash.makeData() { + result[.selfie(hash: fileHash.makeData())] = text + } + case let .secureValueErrorFrontSide(_, fileHash, text): + if frontSideHash == fileHash.makeData() { + result[.frontSide(hash: fileHash.makeData())] = text + } + case let .secureValueErrorReverseSide(_, fileHash, text): + if backSideHash == fileHash.makeData() { + result[.backSide(hash: fileHash.makeData())] = text + } + } + } + return result +} diff --git a/submodules/TelegramCore/TelegramCore/SecureIdVerificationDocumentReference.swift b/submodules/TelegramCore/TelegramCore/SecureIdVerificationDocumentReference.swift new file mode 100644 index 0000000000..0e46208fdd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecureIdVerificationDocumentReference.swift @@ -0,0 +1,23 @@ +import Foundation + +public enum SecureIdVerificationDocumentReference: Equatable { + case remote(SecureIdFileReference) + case uploaded(UploadedSecureIdFile) + + public static func ==(lhs: SecureIdVerificationDocumentReference, rhs: SecureIdVerificationDocumentReference) -> Bool { + switch lhs { + case let .remote(file): + if case .remote(file) = rhs { + return true + } else { + return false + } + case let .uploaded(file): + if case .uploaded(file) = rhs { + return true + } else { + return false + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Serialization.swift b/submodules/TelegramCore/TelegramCore/Serialization.swift new file mode 100644 index 0000000000..2f39867c53 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Serialization.swift @@ -0,0 +1,288 @@ +import Foundation +#if os(macOS) + import MtProtoKitMac +#else + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +#if os(macOS) +private let apiPrefix = "TelegramCoreMac.Api." +#else +private let apiPrefix = "TelegramCore.Api." +#endif + +private let apiPrefixLength = apiPrefix.count + +private let redactChildrenOfType: [String: Set] = [ + "Message.message": Set(["message"]), + "Updates.updateShortMessage": Set(["message"]), + "Updates.updateShortChatMessage": Set(["message"]), + "BotInlineMessage.botInlineMessageText": Set(["message"]), + "DraftMessage.draftMessage": Set(["message"]), + "InputSingleMedia.inputSingleMedia": Set(["message"]), + "InputContact.inputPhoneContact": Set(["phone"]), + "User.user": Set(["phone"]), + "Update.updateUserPhone": Set(["phone"]) +] + +private let redactFunctionParameters: [String: Set] = [ + "messages.sendMessage": Set(["message"]), + "messages.sendMedia": Set(["message"]), + "messages.saveDraft": Set(["message"]), + "messages.getWebPagePreview": Set(["message"]) +] + +func apiFunctionDescription(of desc: FunctionDescription) -> String { + var result = desc.name + if !desc.parameters.isEmpty { + result.append("(") + var first = true + for param in desc.parameters { + if first { + first = false + } else { + result.append(", ") + } + result.append(param.0) + result.append(": ") + + var redactParam = false + if let redactParams = redactFunctionParameters[desc.name] { + redactParam = redactParams.contains(param.0) + } + + if redactParam, Logger.shared.redactSensitiveData { + result.append("[[redacted]]") + } else { + result.append(recursiveDescription(redact: Logger.shared.redactSensitiveData, of: param.1)) + } + } + result.append(")") + } + return result +} + +func apiShortFunctionDescription(of desc: FunctionDescription) -> String { + return desc.name +} + +private func recursiveDescription(redact: Bool, of value: Any) -> String { + let mirror = Mirror(reflecting: value) + var result = "" + if let displayStyle = mirror.displayStyle { + switch displayStyle { + case .enum: + result.append(_typeName(mirror.subjectType)) + if result.hasPrefix(apiPrefix) { + result.removeSubrange(result.startIndex ..< result.index(result.startIndex, offsetBy: apiPrefixLength)) + } + + if let value = value as? TypeConstructorDescription { + let (consName, fields) = value.descriptionFields() + result.append(".") + result.append(consName) + + let redactChildren: Set? + if redact { + redactChildren = redactChildrenOfType[result] + } else { + redactChildren = nil + } + + if !fields.isEmpty { + result.append("(") + var first = true + for (fieldName, fieldValue) in fields { + if first { + first = false + } else { + result.append(", ") + } + var redactValue: Bool = false + if let redactChildren = redactChildren, redactChildren.contains("*") { + redactValue = true + } + + result.append(fieldName) + result.append(": ") + if let redactChildren = redactChildren, redactChildren.contains(fieldName) { + redactValue = true + } + + if redactValue { + result.append("[[redacted]]") + } else { + result.append(recursiveDescription(redact: redact, of: fieldValue)) + } + } + result.append(")") + } + } else { + inner: for child in mirror.children { + if let label = child.label { + result.append(".") + result.append(label) + } + let redactChildren: Set? + if redact { + redactChildren = redactChildrenOfType[result] + } else { + redactChildren = nil + } + let valueMirror = Mirror(reflecting: child.value) + if let displayStyle = valueMirror.displayStyle { + switch displayStyle { + case .tuple: + var hadChildren = false + for child in valueMirror.children { + if !hadChildren { + hadChildren = true + result.append("(") + } else { + result.append(", ") + } + var redactValue: Bool = false + if let redactChildren = redactChildren, redactChildren.contains("*") { + redactValue = true + } + if let label = child.label { + result.append(label) + result.append(": ") + if let redactChildren = redactChildren, redactChildren.contains(label) { + redactValue = true + } + } + + if redactValue { + result.append("[[redacted]]") + } else { + result.append(recursiveDescription(redact: redact, of: child.value)) + } + } + if hadChildren { + result.append(")") + } + default: + break + } + } else { + result.append("(") + result.append(String(describing: child.value)) + result.append(")") + } + break + } + } + case .collection: + result.append("[") + var isFirst = true + for child in mirror.children { + if isFirst { + isFirst = false + } else { + result.append(", ") + } + result.append(recursiveDescription(redact: redact, of: child.value)) + } + result.append("]") + default: + result.append("\(value)") + } + } else { + result.append("\(value)") + } + return result +} + +public class BoxedMessage: NSObject { + public let body: Any + public init(_ body: Any) { + self.body = body + } + + override public var description: String { + get { + return recursiveDescription(redact: Logger.shared.redactSensitiveData, of: self.body) + } + } +} + +public class Serialization: NSObject, MTSerialization { + public func currentLayer() -> UInt { + return 102 + } + + public func parseMessage(_ data: Data!) -> Any! { + if let body = Api.parse(Buffer(data: data)) { + return BoxedMessage(body) + } + return nil + } + + public func exportAuthorization(_ datacenterId: Int32, data: AutoreleasingUnsafeMutablePointer) -> MTExportAuthorizationResponseParser! + { + let functionContext = Api.functions.auth.exportAuthorization(dcId: datacenterId) + data.pointee = functionContext.1.makeData() as NSData + return { data -> MTExportedAuthorizationData? in + if let exported = functionContext.2.parse(Buffer(data: data)) { + switch exported { + case let .exportedAuthorization(id, bytes): + return MTExportedAuthorizationData(authorizationBytes: bytes.makeData(), authorizationId: id) + } + } else { + return nil + } + } + } + + public func importAuthorization(_ authId: Int32, bytes: Data!) -> Data! { + return Api.functions.auth.importAuthorization(id: authId, bytes: Buffer(data: bytes)).1.makeData() + } + + public func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer) -> MTRequestDatacenterAddressListParser! { + let (_, buffer, parser) = Api.functions.help.getConfig() + data.pointee = buffer.makeData() as NSData + return { response -> MTDatacenterAddressListData? in + if let config = parser.parse(Buffer(data: response)) { + switch config { + case let .config(config): + var addressDict: [NSNumber: [Any]] = [:] + for option in config.dcOptions { + switch option { + case let .dcOption(flags, id, ipAddress, port, secret): + if addressDict[id as NSNumber] == nil { + addressDict[id as NSNumber] = [] + } + let preferForMedia = (flags & (1 << 1)) != 0 + let restrictToTcp = (flags & (1 << 2)) != 0 + let isCdn = (flags & (1 << 3)) != 0 + let preferForProxy = (flags & (1 << 4)) != 0 + addressDict[id as NSNumber]!.append(MTDatacenterAddress(ip: ipAddress, port: UInt16(port), preferForMedia: preferForMedia, restrictToTcp: restrictToTcp, cdn: isCdn, preferForProxy: preferForProxy, secret: secret?.makeData())!) + break + } + } + return MTDatacenterAddressListData(addressList: addressDict) + } + + } + return nil + } + } + + public func requestNoop(_ data: AutoreleasingUnsafeMutablePointer!) -> MTRequestNoopParser! { + let (_, buffer, parser) = Api.functions.help.test() + data.pointee = buffer.makeData() as NSData + + return { response -> AnyObject? in + if let _ = parser.parse(Buffer(data: response)) { + return true as NSNumber + } else { + return nil + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift b/submodules/TelegramCore/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift new file mode 100644 index 0000000000..8859413bd9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift @@ -0,0 +1,35 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func setSecretChatMessageAutoremoveTimeoutInteractively(account: Account, peerId: PeerId, timeout: Int32?) -> Signal { + return account.postbox.transaction { transaction -> Void in + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat, let state = transaction.getPeerChatState(peerId) as? SecretChatState { + if state.messageAutoremoveTimeout != timeout { + let updatedPeer = peer.withUpdatedMessageAutoremoveTimeout(timeout) + let updatedState = state.withUpdatedMessageAutoremoveTimeout(timeout) + if !updatedPeer.isEqual(peer) { + updatePeers(transaction: transaction, peers: [updatedPeer], update: { $1 }) + } + if updatedState != state { + transaction.setPeerChatState(peerId, state: updatedState) + } + + let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.messageAutoremoveTimeoutUpdated(timeout == nil ? 0 : timeout!))), replyToMessageId: nil, localGroupingKey: nil))]) + } + } + } +} + +public func addSecretChatMessageScreenshot(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Void in + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat, let state = transaction.getPeerChatState(peerId) as? SecretChatState { + let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil))]) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SingleMessageView.swift b/submodules/TelegramCore/TelegramCore/SingleMessageView.swift new file mode 100644 index 0000000000..45c3c96d4c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SingleMessageView.swift @@ -0,0 +1,108 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func singleMessageView(account: Account, messageId: MessageId, loadIfNotExists: Bool) -> Signal { + return Signal { subscriber in + let loadedMessage = account.postbox.transaction { transaction -> Signal in + if transaction.getMessage(messageId) == nil, loadIfNotExists { + return fetchMessage(transaction: transaction, account: account, messageId: messageId) + } else { + return .complete() + } + } |> switchToLatest + + let disposable = loadedMessage.start() + let viewDisposable = account.postbox.messageView(messageId).start(next: { view in + subscriber.putNext(view) + }) + + return ActionDisposable { + disposable.dispose() + viewDisposable.dispose() + } + } +} + +private func fetchMessage(transaction: Transaction, account: Account, messageId: MessageId) -> Signal { + if let peer = transaction.getPeer(messageId.peerId) { + var signal: Signal? + if messageId.peerId.namespace == Namespaces.Peer.CloudUser || messageId.peerId.namespace == Namespaces.Peer.CloudGroup { + signal = account.network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + } else if messageId.peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = account.network.request(Api.functions.channels.getMessages(channel: inputChannel, id: [Api.InputMessage.inputMessageID(id: messageId.id)])) + } + } + if let signal = signal { + return signal + |> `catch` { _ -> Signal in + return .single(.messages(messages: [], chats: [], users: [])) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + let apiMessages: [Api.Message] + let apiChats: [Api.Chat] + let apiUsers: [Api.User] + switch result { + case let .messages(messages, chats, users): + apiMessages = messages + apiChats = chats + apiUsers = users + case let .messagesSlice(_, _, _, messages, chats, users): + apiMessages = messages + apiChats = chats + apiUsers = users + case let .channelMessages(_, _, _, messages, chats, users): + apiMessages = messages + apiChats = chats + apiUsers = users + case .messagesNotModified: + apiMessages = [] + apiChats = [] + apiUsers = [] + } + + var peers: [PeerId: Peer] = [:] + + for user in apiUsers { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in apiChats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in + return updated + }) + + for message in apiMessages { + if let message = StoreMessage(apiMessage: message) { + let _ = transaction.addMessages([message], location: .Random) + } + } + } + } + } else { + return .complete() + } + } else { + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/SourceReferenceMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/SourceReferenceMessageAttribute.swift new file mode 100644 index 0000000000..a510222be2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SourceReferenceMessageAttribute.swift @@ -0,0 +1,31 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class SourceReferenceMessageAttribute: MessageAttribute { + public let messageId: MessageId + public let associatedMessageIds: [MessageId] = [] + public let associatedPeerIds: [PeerId] + + public init(messageId: MessageId) { + self.messageId = messageId + self.associatedPeerIds = [messageId.peerId] + } + + required public init(decoder: PostboxDecoder) { + let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i", orElse: 0) + self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) + self.associatedPeerIds = [self.messageId.peerId] + } + + public func encode(_ encoder: PostboxEncoder) { + let namespaceAndId = Int64(self.messageId.namespace) | (Int64(self.messageId.id) << 32) + encoder.encodeInt64(namespaceAndId, forKey: "i") + encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") + } +} + + diff --git a/submodules/TelegramCore/TelegramCore/SplitTest.swift b/submodules/TelegramCore/TelegramCore/SplitTest.swift new file mode 100644 index 0000000000..2c5ccbe724 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SplitTest.swift @@ -0,0 +1,33 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public protocol SplitTestEvent: RawRepresentable where RawValue == String { +} + +public protocol SplitTestConfiguration { + static var defaultValue: Self { get } +} + +public protocol SplitTest { + associatedtype Configuration: SplitTestConfiguration + associatedtype Event: SplitTestEvent + + var postbox: Postbox { get } + var bucket: String? { get } + var configuration: Configuration { get } + + init(postbox: Postbox, bucket: String?, configuration: Configuration) +} + +extension SplitTest { + public func addEvent(_ event: Self.Event, data: JSON = []) { + if let bucket = self.bucket { + //TODO: merge additional data + addAppLogEvent(postbox: self.postbox, time: Date().timeIntervalSince1970, type: event.rawValue, peerId: nil, data: ["bucket": bucket]) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StandaloneSendMessage.swift b/submodules/TelegramCore/TelegramCore/StandaloneSendMessage.swift new file mode 100644 index 0000000000..32da881585 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StandaloneSendMessage.swift @@ -0,0 +1,177 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum StandaloneMedia { + case image(Data) + case file(data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) +} + +private enum StandaloneMessageContent { + case text(String) + case media(Api.InputMedia, String) +} + +private enum StandaloneSendMessageEvent { + case result(StandaloneMessageContent) + case progress(Float) +} + +public enum StandaloneSendMessageError { + case generic +} + +public func standaloneSendMessage(account: Account, peerId: PeerId, text: String, attributes: [MessageAttribute], media: StandaloneMedia?, replyToMessageId: MessageId?) -> Signal { + let content: Signal + if let media = media { + switch media { + case let .image(data): + content = uploadedImage(account: account, data: data) + |> mapError { _ -> StandaloneSendMessageError in return .generic } + |> map { next -> StandaloneSendMessageEvent in + switch next { + case let .progress(progress): + return .progress(progress) + case let .result(media): + return .result(.media(media, text)) + } + } + case let .file(data, mimeType, attributes): + content = uploadedFile(account: account, data: data, mimeType: mimeType, attributes: attributes) + |> mapError { _ -> StandaloneSendMessageError in return .generic } + |> map { next -> StandaloneSendMessageEvent in + switch next { + case let .progress(progress): + return .progress(progress) + case let .result(media): + return .result(.media(media, text)) + } + } + } + } else { + content = .single(.result(.text(text))) + } + + return content + |> mapToSignal { event -> Signal in + switch event { + case let .progress(progress): + return .single(progress) + case let .result(result): + let sendContent = sendMessageContent(account: account, peerId: peerId, attributes: attributes, content: result) |> map({ _ -> Float in return 1.0 }) + return .single(1.0) |> then(sendContent |> mapError { _ -> StandaloneSendMessageError in return .generic }) + + } + } +} + +private func sendMessageContent(account: Account, peerId: PeerId, attributes: [MessageAttribute], content: StandaloneMessageContent) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if peerId.namespace == Namespaces.Peer.SecretChat { + return .complete() + } else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + var uniqueId: Int64 = arc4random64() + //var forwardSourceInfoAttribute: ForwardSourceInfoAttribute? + var messageEntities: [Api.MessageEntity]? + var replyMessageId: Int32? + + var flags: Int32 = 0 + + flags |= (1 << 7) + + for attribute in attributes { + if let replyAttribute = attribute as? ReplyMessageAttribute { + replyMessageId = replyAttribute.messageId.id + } else if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute { + uniqueId = outgoingInfo.uniqueId + } else if let _ = attribute as? ForwardSourceInfoAttribute { + //forwardSourceInfoAttribute = attribute + } else if let attribute = attribute as? TextEntitiesMessageAttribute { + messageEntities = apiTextAttributeEntities(attribute, associatedPeers: SimpleDictionary()) + } else if let attribute = attribute as? OutgoingContentInfoMessageAttribute { + if attribute.flags.contains(.disableLinkPreviews) { + flags |= Int32(1 << 1) + } + } + } + + if let _ = replyMessageId { + flags |= Int32(1 << 0) + } + if let _ = messageEntities { + flags |= Int32(1 << 3) + } + + let sendMessageRequest: Signal + switch content { + case let .text(text): + sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities)) + |> `catch` { _ -> Signal in + return .complete() + } + case let .media(inputMedia, text): + sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities)) + |> `catch` { _ -> Signal in + return .complete() + } + } + + return sendMessageRequest + |> mapToSignal { result -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } + } else { + return .complete() + } + } + |> switchToLatest +} + +private enum UploadMediaEvent { + case progress(Float) + case result(Api.InputMedia) +} + +private func uploadedImage(account: Account, data: Data) -> Signal { + return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> mapError { _ -> StandaloneSendMessageError in return .generic } + |> map { next -> UploadMediaEvent in + switch next { + case let .inputFile(inputFile): + return .result(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil)) + case .inputSecretFile: + preconditionFailure() + case let .progress(progress): + return .progress(progress) + } + } +} + +private func uploadedFile(account: Account, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal { + return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: data.count, hintFileIsLarge: false) + |> mapError { _ -> PendingMessageUploadError in return .generic } + |> map { next -> UploadMediaEvent in + switch next { + case let .inputFile(inputFile): + return .result(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil)) + case .inputSecretFile: + preconditionFailure() + case let .progress(progress): + return .progress(progress) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StandaloneUploadedMedia.swift b/submodules/TelegramCore/TelegramCore/StandaloneUploadedMedia.swift new file mode 100644 index 0000000000..fdaefcad2d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StandaloneUploadedMedia.swift @@ -0,0 +1,152 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit + import UIKit +#endif + +public enum StandaloneUploadMediaError { + case generic +} + +public struct StandaloneUploadSecretFile { + let file: Api.InputEncryptedFile + let size: Int32 + let key: SecretFileEncryptionKey +} + +public enum StandaloneUploadMediaResult { + case media(AnyMediaReference) +} + +public enum StandaloneUploadMediaEvent { + case progress(Float) + case result(StandaloneUploadMediaResult) +} + +public func standaloneUploadedImage(account: Account, peerId: PeerId, text: String, data: Data, dimensions: CGSize) -> Signal { + return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { next -> Signal in + switch next { + case let .inputFile(inputFile): + return account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { inputPeer -> Signal in + if let inputPeer = inputPeer { + return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil))) + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { media -> Signal in + switch media { + case let .messageMediaPhoto(_, photo, _): + if let photo = photo { + if let mediaImage = telegramMediaImageFromApiPhoto(photo) { + return .single(.result(.media(.standalone(media: mediaImage)))) + } + } + default: + break + } + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + case let .inputSecretFile(file, _, key): + return account.postbox.transaction { transaction -> Api.InputEncryptedChat? in + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + return Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash) + } + return nil + } + |> introduceError(StandaloneUploadMediaError.self) + |> mapToSignal { inputChat -> Signal in + guard let inputChat = inputChat else { + return .fail(.generic) + } + return account.network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file)) + |> mapError { _ -> StandaloneUploadMediaError in return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .encryptedFile(id, accessHash, size, dcId, _): + return .single(.result(.media(.standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: SecretFileMediaResource(fileId: id, accessHash: accessHash, containerSize: size, decryptedSize: Int32(data.count), datacenterId: Int(dcId), key: key))], immediateThumbnailData: nil, reference: nil, partialReference: nil))))) + case .encryptedFileEmpty: + return .fail(.generic) + } + } + } + case let .progress(progress): + return .single(.progress(progress)) + } + } +} + +public func standaloneUploadedFile(account: Account, peerId: PeerId, text: String, source: MultipartUploadSource, mimeType: String, attributes: [TelegramMediaFileAttribute], hintFileIsLarge: Bool) -> Signal { + return multipartUpload(network: account.network, postbox: account.postbox, source: source, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)), hintFileSize: nil, hintFileIsLarge: hintFileIsLarge) + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { next -> Signal in + switch next { + case let .inputFile(inputFile): + return account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { inputPeer -> Signal in + if let inputPeer = inputPeer { + return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil))) + |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapToSignal { media -> Signal in + switch media { + case let .messageMediaDocument(_, document, _): + if let document = document { + if let mediaFile = telegramMediaFileFromApiDocument(document) { + return .single(.result(.media(.standalone(media: mediaFile)))) + } + } + default: + break + } + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + case let .inputSecretFile(file, size, key): + return account.postbox.transaction { transaction -> Api.InputEncryptedChat? in + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + return Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash) + } + return nil + } + |> introduceError(StandaloneUploadMediaError.self) + |> mapToSignal { inputChat -> Signal in + guard let inputChat = inputChat else { + return .fail(.generic) + } + return account.network.request(Api.functions.messages.uploadEncryptedFile(peer: inputChat, file: file)) + |> mapError { _ -> StandaloneUploadMediaError in return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .encryptedFile(id, accessHash, size, dcId, _): + let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: SecretFileMediaResource(fileId: id, accessHash: accessHash, containerSize: size, decryptedSize: size, datacenterId: Int(dcId), key: key), previewRepresentations: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: attributes) + + return .single(.result(.media(.standalone(media: media)))) + case .encryptedFileEmpty: + return .fail(.generic) + } + } + } + case let .progress(progress): + return .single(.progress(progress)) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StickerManagement.swift b/submodules/TelegramCore/TelegramCore/StickerManagement.swift new file mode 100644 index 0000000000..964bf0dbc5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StickerManagement.swift @@ -0,0 +1,122 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif +import TelegramCorePrivateModule + +private func hashForIdsReverse(_ ids: [Int64]) -> Int32 { + var acc: UInt32 = 0 + + for id in ids { + let low = UInt32(UInt64(bitPattern: id) & (0xffffffff as UInt64)) + let high = UInt32((UInt64(bitPattern: id) >> 32) & (0xffffffff as UInt64)) + + acc = (acc &* 20261) &+ high + acc = (acc &* 20261) &+ low + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +func manageStickerPacks(network: Network, postbox: Postbox) -> Signal { + return (postbox.transaction { transaction -> Void in + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .stickers, content: .sync) + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: .masks, content: .sync) + addSynchronizeSavedGifsOperation(transaction: transaction, operation: .sync) + addSynchronizeSavedStickersOperation(transaction: transaction, operation: .sync) + addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .sync) + } |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} + +func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> Signal in + let initialPacks = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks) + var initialPackMap: [Int64: FeaturedStickerPackItem] = [:] + for entry in initialPacks { + let item = entry.contents as! FeaturedStickerPackItem + initialPackMap[FeaturedStickerPackItemId(entry.id).packId] = item + } + + let initialPackIds = initialPacks.map { + return FeaturedStickerPackItemId($0.id).packId + } + let initialHash: Int32 = hashForIdsReverse(initialPackIds) + return network.request(Api.functions.messages.getFeaturedStickers(hash: initialHash)) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + switch result { + case .featuredStickersNotModified: + break + case let .featuredStickers(_, sets, unread): + let unreadIds = Set(unread) + var updatedPacks: [FeaturedStickerPackItem] = [] + for set in sets { + var (info, items) = parsePreviewStickerSet(set) + if let previousPack = initialPackMap[info.id.id] { + if previousPack.info.hash == info.hash { + items = previousPack.topItems + } + } + updatedPacks.append(FeaturedStickerPackItem(info: info, topItems: items, unread: unreadIds.contains(info.id.id))) + } + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, items: updatedPacks.map { OrderedItemListEntry(id: FeaturedStickerPackItemId($0.info.id.id).rawValue, contents: $0) }) + } + } + } + } |> switchToLatest +} + +public func preloadedFeaturedStickerSet(network: Network, postbox: Postbox, id: ItemCollectionId) -> Signal { + return postbox.transaction { transaction -> Signal in + if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { + if pack.topItems.count < 5 && pack.topItems.count < pack.info.count { + return requestStickerSet(postbox: postbox, network: network, reference: .id(id: pack.info.id.id, accessHash: pack.info.accessHash)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + return postbox.transaction { transaction -> Void in + if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { + var items = result.items.map({ $0 as? StickerPackItem }).flatMap({ $0 }) + if items.count > 5 { + items.removeSubrange(5 ..< items.count) + } + transaction.updateOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue, item: FeaturedStickerPackItem(info: pack.info, topItems: items, unread: pack.unread)) + } + } + } else { + return .complete() + } + } + } + } + return .complete() + } |> switchToLatest +} + +func parsePreviewStickerSet(_ set: Api.StickerSetCovered) -> (StickerPackCollectionInfo, [StickerPackItem]) { + switch set { + case let .stickerSetCovered(set, cover): + let info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks) + var items: [StickerPackItem] = [] + if let file = telegramMediaFileFromApiDocument(cover), let id = file.id { + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: id.id), file: file, indexKeys: [])) + } + return (info, items) + case let .stickerSetMultiCovered(set, covers): + let info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks) + var items: [StickerPackItem] = [] + for cover in covers { + if let file = telegramMediaFileFromApiDocument(cover), let id = file.id { + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: id.id), file: file, indexKeys: [])) + } + } + return (info, items) + } +} diff --git a/submodules/TelegramCore/TelegramCore/StickerPack.swift b/submodules/TelegramCore/TelegramCore/StickerPack.swift new file mode 100644 index 0000000000..470f4090c7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StickerPack.swift @@ -0,0 +1,198 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public struct StickerPackCollectionInfoFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public init(_ flags: StickerPackCollectionInfoFlags) { + var rawValue: Int32 = 0 + + if flags.contains(StickerPackCollectionInfoFlags.masks) { + rawValue |= StickerPackCollectionInfoFlags.masks.rawValue + } + + if flags.contains(StickerPackCollectionInfoFlags.official) { + rawValue |= StickerPackCollectionInfoFlags.official.rawValue + } + + self.rawValue = rawValue + } + + public static let masks = StickerPackCollectionInfoFlags(rawValue: 1) + public static let official = StickerPackCollectionInfoFlags(rawValue: 2) +} + + +public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { + public let id: ItemCollectionId + public let flags: StickerPackCollectionInfoFlags + public let accessHash: Int64 + public let title: String + public let shortName: String + public let thumbnail: TelegramMediaImageRepresentation? + public let hash: Int32 + public let count: Int32 + + public init(id: ItemCollectionId, flags: StickerPackCollectionInfoFlags, accessHash: Int64, title: String, shortName: String, thumbnail: TelegramMediaImageRepresentation?, hash: Int32, count: Int32) { + self.id = id + self.flags = flags + self.accessHash = accessHash + self.title = title + self.shortName = shortName + self.thumbnail = thumbnail + self.hash = hash + self.count = count + } + + public init(decoder: PostboxDecoder) { + self.id = ItemCollectionId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) + self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) + self.title = decoder.decodeStringForKey("t", orElse: "") + self.shortName = decoder.decodeStringForKey("s", orElse: "") + self.thumbnail = decoder.decodeObjectForKey("th", decoder: { TelegramMediaImageRepresentation(decoder: $0) }) as? TelegramMediaImageRepresentation + self.hash = decoder.decodeInt32ForKey("h", orElse: 0) + self.flags = StickerPackCollectionInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.count = decoder.decodeInt32ForKey("n", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.id.namespace, forKey: "i.n") + encoder.encodeInt64(self.id.id, forKey: "i.i") + encoder.encodeInt64(self.accessHash, forKey: "a") + encoder.encodeString(self.title, forKey: "t") + encoder.encodeString(self.shortName, forKey: "s") + if let thumbnail = self.thumbnail { + encoder.encodeObject(thumbnail, forKey: "th") + } else { + encoder.encodeNil(forKey: "th") + } + encoder.encodeInt32(self.hash, forKey: "h") + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + encoder.encodeInt32(self.count, forKey: "n") + } + + public static func ==(lhs: StickerPackCollectionInfo, rhs: StickerPackCollectionInfo) -> Bool { + if lhs.id != rhs.id { + return false + } + + if lhs.title != rhs.title { + return false + } + + if lhs.shortName != rhs.shortName { + return false + } + + if lhs.hash != rhs.hash { + return false + } + + if lhs.flags != rhs.flags { + return false + } + + if lhs.count != rhs.count { + return false + } + + return true + } +} + +public final class StickerPackItem: ItemCollectionItem, Equatable { + public let index: ItemCollectionItemIndex + public let file: TelegramMediaFile + public let indexKeys: [MemoryBuffer] + + public init(index: ItemCollectionItemIndex, file: TelegramMediaFile, indexKeys: [MemoryBuffer]) { + self.index = index + self.file = file + self.indexKeys = indexKeys + } + + public init(decoder: PostboxDecoder) { + self.index = ItemCollectionItemIndex(index: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) + self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile + self.indexKeys = decoder.decodeBytesArrayForKey("s") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.index.index, forKey: "i.n") + encoder.encodeInt64(self.index.id, forKey: "i.i") + encoder.encodeObject(self.file, forKey: "f") + encoder.encodeBytesArray(self.indexKeys, forKey: "s") + } + + public static func ==(lhs: StickerPackItem, rhs: StickerPackItem) -> Bool { + return lhs.index == rhs.index && lhs.file == rhs.file && lhs.indexKeys == rhs.indexKeys + } + + public func getStringRepresentationsOfIndexKeys() -> [String] { + var stringRepresentations: [String] = [] + for key in self.indexKeys { + key.withDataNoCopy { data in + if let string = String(data: data, encoding: .utf8) { + stringRepresentations.append(string) + } + } + } + return stringRepresentations + } +} + +func telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: Int32, size: Api.PhotoSize) -> TelegramMediaImageRepresentation? { + switch size { + case let .photoCachedSize(_, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) + return TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource) + } + case let .photoSize(_, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) + return TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource) + } + case .photoStrippedSize: + return nil + case .photoSizeEmpty: + return nil + } +} + +extension StickerPackCollectionInfo { + convenience init(apiSet: Api.StickerSet, namespace: ItemCollectionId.Namespace) { + switch apiSet { + case let .stickerSet(flags, _, id, accessHash, title, shortName, thumb, thumbDcId, count, nHash): + var setFlags: StickerPackCollectionInfoFlags = StickerPackCollectionInfoFlags() + if (flags & (1 << 2)) != 0 { + setFlags.insert(.official) + } + if (flags & (1 << 3)) != 0 { + setFlags.insert(.masks) + } + + var thumbnailRepresentation: TelegramMediaImageRepresentation? + if let thumb = thumb, let thumbDcId = thumbDcId { + thumbnailRepresentation = telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb) + } + + self.init(id: ItemCollectionId(namespace: namespace, id: id), flags: setFlags, accessHash: accessHash, title: title, shortName: shortName, thumbnail: thumbnailRepresentation, hash: nHash, count: count) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StickerPackInteractiveOperations.swift b/submodules/TelegramCore/TelegramCore/StickerPackInteractiveOperations.swift new file mode 100644 index 0000000000..3394b49567 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StickerPackInteractiveOperations.swift @@ -0,0 +1,84 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func addStickerPackInteractively(postbox: Postbox, info: StickerPackCollectionInfo, items: [ItemCollectionItem]) -> Signal { + return postbox.transaction { transaction -> Void in + let namespace: SynchronizeInstalledStickerPacksOperationNamespace? + switch info.id.namespace { + case Namespaces.ItemCollection.CloudStickerPacks: + namespace = .stickers + case Namespaces.ItemCollection.CloudMaskPacks: + namespace = .masks + default: + namespace = nil + } + if let namespace = namespace { + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespace, content: .add([info.id])) + var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! StickerPackCollectionInfo } + if let index = updatedInfos.index(where: { $0.id == info.id }) { + let currentInfo = updatedInfos[index] + updatedInfos.remove(at: index) + updatedInfos.insert(currentInfo, at: 0) + } else { + updatedInfos.insert(info, at: 0) + transaction.replaceItemCollectionItems(collectionId: info.id, items: items) + } + transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) }) + } + } +} + +public enum RemoveStickerPackOption { + case delete + case archive +} + +public func removeStickerPackInteractively(postbox: Postbox, id: ItemCollectionId, option: RemoveStickerPackOption) -> Signal { + return postbox.transaction { transaction -> Void in + let namespace: SynchronizeInstalledStickerPacksOperationNamespace? + switch id.namespace { + case Namespaces.ItemCollection.CloudStickerPacks: + namespace = .stickers + case Namespaces.ItemCollection.CloudMaskPacks: + namespace = .masks + default: + namespace = nil + } + if let namespace = namespace { + let content: AddSynchronizeInstalledStickerPacksOperationContent + switch option { + case .delete: + content = .remove([id]) + case .archive: + content = .archive([id]) + } + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespace, content: content) + transaction.removeItemCollection(collectionId: id) + } + } +} + +public func markFeaturedStickerPacksAsSeenInteractively(postbox: Postbox, ids: [ItemCollectionId]) -> Signal { + return postbox.transaction { transaction -> Void in + let idsSet = Set(ids) + var items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks) + var readIds = Set() + for i in 0 ..< items.count { + let item = (items[i].contents as! FeaturedStickerPackItem) + if item.unread && idsSet.contains(item.info.id) { + readIds.insert(item.info.id) + items[i] = OrderedItemListEntry(id: items[i].id, contents: FeaturedStickerPackItem(info: item.info, topItems: item.topItems, unread: false)) + } + } + if !readIds.isEmpty { + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, items: items) + addSynchronizeMarkFeaturedStickerPacksAsSeenOperation(transaction: transaction, ids: Array(readIds)) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StickerSetInstallation.swift b/submodules/TelegramCore/TelegramCore/StickerSetInstallation.swift new file mode 100644 index 0000000000..53d14c86f9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StickerSetInstallation.swift @@ -0,0 +1,225 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + + +public enum RequestStickerSetError { + case generic + case invalid +} + +public enum RequestStickerSetResult { + case local(info: ItemCollectionInfo, items: [ItemCollectionItem]) + case remote(info: ItemCollectionInfo, items: [ItemCollectionItem], installed: Bool) + + public var items: [ItemCollectionItem] { + switch self { + case let .local(_, items): + return items + case let .remote(_, items, _): + return items + } + } +} + +public func requestStickerSet(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal { + let collectionId: ItemCollectionId? + let input: Api.InputStickerSet + + switch reference { + case let .name(name): + collectionId = nil + input = .inputStickerSetShortName(shortName: name) + case let .id(id, accessHash): + collectionId = ItemCollectionId(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: id) + input = .inputStickerSetID(id: id, accessHash: accessHash) + } + + let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, NoError> = { collectionId in + return postbox.transaction { transaction -> (ItemCollectionInfo, [ItemCollectionItem])? in + return transaction.getItemCollectionInfoItems(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: collectionId) + } + } + + let remoteSignal = network.request(Api.functions.messages.getStickerSet(stickerset: input)) + |> mapError { _ -> RequestStickerSetError in + return .invalid + } + |> map { result -> RequestStickerSetResult in + var items: [ItemCollectionItem] = [] + let info: ItemCollectionInfo + let installed: Bool + switch result { + case let .stickerSet(set, packs, documents): + info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks) + + switch set { + case let .stickerSet(data): + installed = (data.flags & (1 << 0) != 0) + } + + var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + let key = ValueBoxKey(text).toMemoryBuffer() + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if indexKeysByFile[mediaId] == nil { + indexKeysByFile[mediaId] = [key] + } else { + indexKeysByFile[mediaId]!.append(key) + } + } + break + } + } + + for apiDocument in documents { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + let fileIndexKeys: [MemoryBuffer] + if let indexKeys = indexKeysByFile[id] { + fileIndexKeys = indexKeys + } else { + fileIndexKeys = [] + } + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys)) + } + } + } + return .remote(info: info, items: items, installed: installed) + } + + if let collectionId = collectionId { + return localSignal(collectionId) |> mapError {_ in return .generic} |> mapToSignal { result -> Signal in + if let result = result { + return .single(.local(info: result.0, items: result.1)) + } else { + return remoteSignal + } + } + } else { + return remoteSignal + } +} + +public enum InstallStickerSetError { + case generic +} + +public enum InstallStickerSetResult { + case successful + case archived([CoveredStickerSet]) +} + +public final class CoveredStickerSet : Equatable { + let items: [StickerPackItem] + let info: StickerPackCollectionInfo + public init(info: StickerPackCollectionInfo, items: [StickerPackItem]) { + self.items = items + self.info = info + } + + public static func ==(lhs: CoveredStickerSet, rhs: CoveredStickerSet) -> Bool { + return lhs.items == rhs.items && lhs.info == rhs.info + } +} + +public func installStickerSetInteractively(account: Account, info: StickerPackCollectionInfo, items: [ItemCollectionItem]) -> Signal { + + return account.network.request(Api.functions.messages.installStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash), archived: .boolFalse)) |> mapError { _ -> InstallStickerSetError in + return .generic + } |> mapToSignal { result -> Signal in + let addResult:InstallStickerSetResult + switch result { + case .stickerSetInstallResultSuccess: + addResult = .successful + case let .stickerSetInstallResultArchive(sets: archived): + var coveredSets:[CoveredStickerSet] = [] + for archived in archived { + let apiDocuments:[Api.Document] + let apiSet:Api.StickerSet + switch archived { + case let .stickerSetCovered(set: set, cover: cover): + apiSet = set + apiDocuments = [cover] + case let .stickerSetMultiCovered(set: set, covers: covers): + apiSet = set + apiDocuments = covers + } + + let info = StickerPackCollectionInfo(apiSet: apiSet, namespace: Namespaces.ItemCollection.CloudStickerPacks) + + var items:[StickerPackItem] = [] + for apiDocument in apiDocuments { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: [])) + } + } + coveredSets.append(CoveredStickerSet(info: info, items: items)) + } + addResult = .archived(coveredSets) + } + + + return account.postbox.transaction { transaction -> Void in + var collections = transaction.getCollectionsItems(namespace: info.id.namespace) + + var removableIndexes:[Int] = [] + for i in 0 ..< collections.count { + if collections[i].0 == info.id { + removableIndexes.append(i) + } + if case let .archived(sets) = addResult { + for set in sets { + if collections[i].0 == set.info.id { + removableIndexes.append(i) + } + } + } + } + + for index in removableIndexes.reversed() { + collections.remove(at: index) + } + + collections.insert((info.id, info, items), at: 0) + + transaction.replaceItemCollections(namespace: info.id.namespace, itemCollections: collections) + } |> map { _ in return addResult} |> mapError {_ in return .generic} + } +} + + +public func uninstallStickerSetInteractively(account: Account, info: StickerPackCollectionInfo) -> Signal { + return account.network.request(Api.functions.messages.uninstallStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { result -> Signal in + switch result { + case .boolTrue: + return account.postbox.transaction { transaction -> Void in + var collections = transaction.getCollectionsItems(namespace: info.id.namespace) + + for i in 0 ..< collections.count { + if collections[i].0 == info.id { + collections.remove(at: i) + break + } + } + + transaction.replaceItemCollections(namespace: info.id.namespace, itemCollections: collections) + } + case .boolFalse: + return .complete() + } + } +} + + diff --git a/submodules/TelegramCore/TelegramCore/StoreMessage_Telegram.swift b/submodules/TelegramCore/TelegramCore/StoreMessage_Telegram.swift new file mode 100644 index 0000000000..27b9d9cbc6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StoreMessage_Telegram.swift @@ -0,0 +1,633 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute], media: [Media], textEntities: [MessageTextEntity]?) -> (MessageTags, GlobalMessageTags) { + var isSecret = false + var isUnconsumedPersonalMention = false + for attribute in attributes { + if let timerAttribute = attribute as? AutoremoveTimeoutMessageAttribute { + if timerAttribute.timeout > 0 && timerAttribute.timeout <= 60 { + isSecret = true + } + } else if let mentionAttribute = attribute as? ConsumablePersonalMentionMessageAttribute { + if !mentionAttribute.consumed { + isUnconsumedPersonalMention = true + } + } + } + + var tags = MessageTags() + var globalTags = GlobalMessageTags() + + if isUnconsumedPersonalMention { + tags.insert(.unseenPersonalMessage) + } + + for attachment in media { + if let _ = attachment as? TelegramMediaImage { + if !isSecret { + tags.insert(.photoOrVideo) + } + } else if let file = attachment as? TelegramMediaFile { + var refinedTag: MessageTags? = .file + var isAnimated = false + inner: for attribute in file.attributes { + switch attribute { + case let .Video(_, _, flags): + if flags.contains(.instantRoundVideo) { + refinedTag = .voiceOrInstantVideo + } else { + if !isSecret { + refinedTag = .photoOrVideo + } else { + refinedTag = nil + } + } + case let .Audio(isVoice, _, _, _, _): + if isVoice { + refinedTag = .voiceOrInstantVideo + } else { + refinedTag = .music + } + break inner + case .Sticker: + refinedTag = nil + break inner + case .Animated: + isAnimated = true + default: + break + } + } + if isAnimated { + refinedTag = nil + } + if let refinedTag = refinedTag { + tags.insert(refinedTag) + } + } else if let webpage = attachment as? TelegramMediaWebpage, case .Loaded = webpage.content { + tags.insert(.webPage) + } else if let action = attachment as? TelegramMediaAction { + switch action.action { + case let .phoneCall(_, discardReason, _): + globalTags.insert(.Calls) + if incoming, let discardReason = discardReason, case .missed = discardReason { + globalTags.insert(.MissedCalls) + } + default: + break + } + } else if let location = attachment as? TelegramMediaMap, location.liveBroadcastingTimeout != nil { + tags.insert(.liveLocation) + } + } + if let textEntities = textEntities, !textEntities.isEmpty && !tags.contains(.webPage) { + for entity in textEntities { + switch entity.type { + case .Url, .Email: + if media.isEmpty || !(media.first is TelegramMediaWebpage) { + tags.insert(.webPage) + } + default: + break + } + } + } + + if !incoming { + assert(true) + } + return (tags, globalTags) +} + +func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? { + switch messsage { + case let .message(flags, _, fromId, toId, _, _, _, _, _, _, _, _, _, _, _, _): + switch toId { + case let .peerUser(userId): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + case .messageEmpty: + return nil + case let .messageService(flags, _, fromId, toId, _, _, _): + switch toId { + case let .peerUser(userId): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + } +} + +func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { + switch message { + case let .message(flags, _, fromId, toId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _): + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + var result = [peerId] + + if let fromId = fromId, PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) != peerId { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId)) + } + + if let fwdHeader = fwdHeader { + switch fwdHeader { + case let .messageFwdHeader(messageFwdHeader): + if let channelId = messageFwdHeader.channelId { + result.append(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)) + } + if let fromId = messageFwdHeader.fromId { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId)) + } + if let savedFromPeer = messageFwdHeader.savedFromPeer { + result.append(savedFromPeer.peerId) + } + } + } + + if let viaBotId = viaBotId { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: viaBotId)) + } + + if let media = media { + switch media { + case let .messageMediaContact(_, _, _, _, userId): + if userId != 0 { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + } + default: + break + } + } + + if let entities = entities { + for entity in entities { + switch entity { + case let .messageEntityMentionName(_, _, userId): + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + default: + break + } + } + } + + return result + case .messageEmpty: + return [] + case let .messageService(flags, _, fromId, toId, _, _, action): + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + var result = [peerId] + + if let fromId = fromId, PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) != peerId { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId)) + } + + switch action { + case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp: + break + case let .messageActionChannelMigrateFrom(_, chatId): + result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)) + case let .messageActionChatAddUser(users): + for id in users { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: id)) + } + case let .messageActionChatCreate(_, users): + for id in users { + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: id)) + } + case let .messageActionChatDeleteUser(userId): + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) + case let .messageActionChatJoinedByLink(inviterId): + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId)) + case let .messageActionChatMigrateTo(channelId): + result.append(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)) + } + + return result + } +} + +func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? { + switch message { + case let .message(flags, _, fromId, toId, _, _, replyToMsgId, _, _, _, _, _, _, _, _, _): + if let replyToMsgId = replyToMsgId { + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + return [MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)] + } + case .messageEmpty: + break + case let .messageService(flags, _, fromId, toId, replyToMsgId, _, _): + if let replyToMsgId = replyToMsgId { + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + return [MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)] + } + } + return nil +} + +func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerId:PeerId) -> (Media?, Int32?) { + if let media = media { + switch media { + case let .messageMediaPhoto(_, photo, ttlSeconds): + if let photo = photo { + if let mediaImage = telegramMediaImageFromApiPhoto(photo) { + return (mediaImage, ttlSeconds) + } + } else { + return (TelegramMediaExpiredContent(data: .image), nil) + } + case let .messageMediaContact(phoneNumber, firstName, lastName, vcard, userId): + let contactPeerId: PeerId? = userId == 0 ? nil : PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + let mediaContact = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: contactPeerId, vCardData: vcard.isEmpty ? nil : vcard) + return (mediaContact, nil) + case let .messageMediaGeo(geo): + let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil) + return (mediaMap, nil) + case let .messageMediaVenue(geo, title, address, provider, venueId, venueType): + let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId, venueType: venueType, liveBroadcastingTimeout: nil) + return (mediaMap, nil) + case let .messageMediaGeoLive(geo, period): + let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period) + return (mediaMap, nil) + case let .messageMediaDocument(_, document, ttlSeconds): + if let document = document { + if let mediaFile = telegramMediaFileFromApiDocument(document) { + return (mediaFile, ttlSeconds) + } + } else { + return (TelegramMediaExpiredContent(data: .file), nil) + } + case let .messageMediaWebPage(webpage): + if let mediaWebpage = telegramMediaWebpageFromApiWebpage(webpage, url: nil) { + return (mediaWebpage, nil) + } + case .messageMediaUnsupported: + return (TelegramMediaUnsupported(), nil) + case .messageMediaEmpty: + break + case let .messageMediaGame(game): + return (TelegramMediaGame(apiGame: game), nil) + case let .messageMediaInvoice(flags, title, description, photo, receiptMsgId, currency, totalAmount, startParam): + var parsedFlags = TelegramMediaInvoiceFlags() + if (flags & (1 << 3)) != 0 { + parsedFlags.insert(.isTest) + } + if (flags & (1 << 1)) != 0 { + parsedFlags.insert(.shippingAddressRequested) + } + return (TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: receiptMsgId.flatMap { MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }, currency: currency, totalAmount: totalAmount, startParam: startParam, flags: parsedFlags), nil) + case let .messageMediaPoll(poll, results): + switch poll { + case let .poll(id, flags, question, answers): + return (TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), text: question, options: answers.map(TelegramMediaPollOption.init(apiOption:)), results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0), nil) + } + } + } + + return (nil, nil) +} + +func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [MessageTextEntity] { + var result: [MessageTextEntity] = [] + for entity in entities { + switch entity { + case .messageEntityUnknown, .inputMessageEntityMentionName: + break + case let .messageEntityMention(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Mention)) + case let .messageEntityHashtag(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) + case let .messageEntityBotCommand(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BotCommand)) + case let .messageEntityUrl(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Url)) + case let .messageEntityEmail(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Email)) + case let .messageEntityBold(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Bold)) + case let .messageEntityItalic(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Italic)) + case let .messageEntityCode(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Code)) + case let .messageEntityPre(offset, length, _): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Pre)) + case let .messageEntityTextUrl(offset, length, url): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextUrl(url: url))) + case let .messageEntityMentionName(offset, length, userId): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextMention(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)))) + case let .messageEntityPhone(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .PhoneNumber)) + case let .messageEntityCashtag(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) + case let .messageEntityUnderline(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Underline)) + case let .messageEntityStrike(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough)) + case let .messageEntityBlockquote(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote)) + } + } + return result +} + +extension StoreMessage { + convenience init?(apiMessage: Api.Message) { + switch apiMessage { + case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate, postAuthor, groupingId): + let peerId: PeerId + var authorId: PeerId? + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + } + + var attributes: [MessageAttribute] = [] + + var forwardInfo: StoreMessageForwardInfo? + if let fwdFrom = fwdFrom { + switch fwdFrom { + case let .messageFwdHeader(_, fromId, fromName, date, channelId, channelPost, postAuthor, savedFromPeer, savedFromMsgId): + var authorId: PeerId? + var sourceId: PeerId? + var sourceMessageId: MessageId? + + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } + if let channelId = channelId { + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + sourceId = peerId + + if let channelPost = channelPost { + sourceMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: channelPost) + } + } + + if let savedFromPeer = savedFromPeer, let savedFromMsgId = savedFromMsgId { + let peerId: PeerId + switch savedFromPeer { + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + } + let messageId: MessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: savedFromMsgId) + attributes.append(SourceReferenceMessageAttribute(messageId: messageId)) + } + + if let authorId = authorId { + forwardInfo = StoreMessageForwardInfo(authorId: authorId, sourceId: sourceId, sourceMessageId: sourceMessageId, date: date, authorSignature: postAuthor) + } else if let sourceId = sourceId { + forwardInfo = StoreMessageForwardInfo(authorId: sourceId, sourceId: sourceId, sourceMessageId: sourceMessageId, date: date, authorSignature: postAuthor) + } else if let postAuthor = postAuthor ?? fromName { + forwardInfo = StoreMessageForwardInfo(authorId: nil, sourceId: nil, sourceMessageId: sourceMessageId, date: date, authorSignature: postAuthor) + } + } + } + + let messageText = message + var medias: [Media] = [] + + var consumableContent: (Bool, Bool)? = nil + + if let media = media { + let (mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId) + if let mediaValue = mediaValue { + medias.append(mediaValue) + + if let expirationTimer = expirationTimer, expirationTimer > 0 { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: expirationTimer, countdownBeginTime: nil)) + + consumableContent = (true, false) + } + } + } + + if let postAuthor = postAuthor { + attributes.append(AuthorSignatureMessageAttribute(signature: postAuthor)) + } + + for case let file as TelegramMediaFile in medias { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel { + if file.isVoice { + consumableContent = (true, (flags & (1 << 5)) == 0) + break + } else if file.isInstantVideo { + consumableContent = (true, (flags & (1 << 5)) == 0) + break + } + } + } + + if let (value, consumed) = consumableContent, value { + attributes.append(ConsumableContentMessageAttribute(consumed: consumed)) + } + + if let viaBotId = viaBotId { + attributes.append(InlineBotMessageAttribute(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: viaBotId), title: nil)) + } + + if let replyToMsgId = replyToMsgId { + attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId))) + } + + if let views = views { + attributes.append(ViewCountMessageAttribute(count: Int(views))) + } + + if let editDate = editDate { + attributes.append(EditedMessageAttribute(date: editDate)) + } + + var entitiesAttribute: TextEntitiesMessageAttribute? + if let entities = entities, !entities.isEmpty { + let attribute = TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)) + entitiesAttribute = attribute + attributes.append(attribute) + } else { + var noEntities = false + loop: for media in medias { + switch media { + case _ as TelegramMediaContact, + _ as TelegramMediaMap: + noEntities = true + break loop + default: + break + } + } + if !noEntities { + let attribute = TextEntitiesMessageAttribute(entities: []) + entitiesAttribute = attribute + attributes.append(attribute) + } + } + + if (flags & (1 << 17)) != 0 { + attributes.append(ContentRequiresValidationMessageAttribute()) + } + + var storeFlags = StoreMessageFlags() + + if let replyMarkup = replyMarkup { + let parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) + attributes.append(parsedReplyMarkup) + if !parsedReplyMarkup.flags.contains(.inline) { + storeFlags.insert(.TopIndexable) + } + } + + if (flags & (1 << 1)) == 0 { + storeFlags.insert(.Incoming) + } + + if (flags & (1 << 4)) != 0 || (flags & (1 << 13)) != 0 { + var notificationFlags: NotificationInfoMessageAttributeFlags = [] + if (flags & (1 << 4)) != 0 { + notificationFlags.insert(.personal) + let notConsumed = (flags & (1 << 5)) != 0 + attributes.append(ConsumablePersonalMentionMessageAttribute(consumed: !notConsumed, pending: false)) + } + if (flags & (1 << 13)) != 0 { + notificationFlags.insert(.muted) + } + attributes.append(NotificationInfoMessageAttribute(flags: notificationFlags)) + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: storeFlags.contains(.Incoming), attributes: attributes, media: medias, textEntities: entitiesAttribute?.entities) + + storeFlags.insert(.CanBeGroupedIntoFeed) + + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, groupingKey: groupingId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias) + case .messageEmpty: + return nil + case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action): + let peerId: PeerId + var authorId: PeerId? + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + if let fromId = fromId { + authorId = PeerId(namespace: Namespaces.Peer.CloudUser, id: fromId) + } else { + authorId = peerId + } + } + + var attributes: [MessageAttribute] = [] + if let replyToMsgId = replyToMsgId { + attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId))) + } + + if (flags & (1 << 17)) != 0 { + attributes.append(ContentRequiresValidationMessageAttribute()) + } + + var storeFlags = StoreMessageFlags() + if (flags & 2) == 0 { + let _ = storeFlags.insert(.Incoming) + } + + if (flags & (1 << 4)) != 0 || (flags & (1 << 13)) != 0 { + var notificationFlags: NotificationInfoMessageAttributeFlags = [] + if (flags & (1 << 4)) != 0 { + notificationFlags.insert(.personal) + } + if (flags & (1 << 13)) != 0 { + notificationFlags.insert(.muted) + } + attributes.append(NotificationInfoMessageAttribute(flags: notificationFlags)) + } + + var media: [Media] = [] + if let action = telegramMediaActionFromApiAction(action) { + media.append(action) + } + + let (tags, globalTags) = tagsForStoreMessage(incoming: storeFlags.contains(.Incoming), attributes: attributes, media: media, textEntities: nil) + + storeFlags.insert(.CanBeGroupedIntoFeed) + + self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StringFormat.swift b/submodules/TelegramCore/TelegramCore/StringFormat.swift new file mode 100644 index 0000000000..3b58878fcd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/StringFormat.swift @@ -0,0 +1,30 @@ +public func dataSizeString(_ size: Int, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { + return dataSizeString(Int64(size), forceDecimal: forceDecimal, decimalSeparator: decimalSeparator) +} + +public func dataSizeString(_ size: Int64, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { + if size >= 1024 * 1024 * 1024 { + let remainder = Int64((Double(size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102.4)).rounded(.down)) + if remainder != 0 || forceDecimal { + return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB" + } else { + return "\(size / (1024 * 1024 * 1024)) GB" + } + } else if size >= 1024 * 1024 { + let remainder = Int64((Double(size % (1024 * 1024)) / (1024.0 * 102.4)).rounded(.down)) + if remainder != 0 || forceDecimal { + return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB" + } else { + return "\(size / (1024 * 1024)) MB" + } + } else if size >= 1024 { + let remainder = (size % (1024)) / (102) + if remainder != 0 || forceDecimal { + return "\(size / 1024)\(decimalSeparator)\(remainder) KB" + } else { + return "\(size / 1024) KB" + } + } else { + return "\(size) B" + } +} diff --git a/submodules/TelegramCore/TelegramCore/SuggestedLocalizationEntry.swift b/submodules/TelegramCore/TelegramCore/SuggestedLocalizationEntry.swift new file mode 100644 index 0000000000..b165799eaf --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SuggestedLocalizationEntry.swift @@ -0,0 +1,55 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public final class SuggestedLocalizationEntry: PreferencesEntry { + public let languageCode: String + public let isSeen: Bool + + init(languageCode: String, isSeen: Bool) { + self.languageCode = languageCode + self.isSeen = isSeen + } + + public init(decoder: PostboxDecoder) { + self.languageCode = decoder.decodeStringForKey("lc", orElse: "en") + self.isSeen = decoder.decodeInt32ForKey("s", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.languageCode, forKey: "lc") + encoder.encodeInt32(self.isSeen ? 1 : 0, forKey: "s") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? SuggestedLocalizationEntry { + return self == to + } else { + return false + } + } + + public static func ==(lhs: SuggestedLocalizationEntry, rhs: SuggestedLocalizationEntry) -> Bool { + return lhs.languageCode == rhs.languageCode && lhs.isSeen == rhs.isSeen + } +} + +public func markSuggestedLocalizationAsSeenInteractively(postbox: Postbox, languageCode: String) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: PreferencesKeys.suggestedLocalization, { current in + if let current = current as? SuggestedLocalizationEntry { + if current.languageCode == languageCode, !current.isSeen { + return SuggestedLocalizationEntry(languageCode: languageCode, isSeen: true) + } + } else { + return SuggestedLocalizationEntry(languageCode: languageCode, isSeen: true) + } + return current + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SupportPeerId.swift b/submodules/TelegramCore/TelegramCore/SupportPeerId.swift new file mode 100644 index 0000000000..bfc1abddc7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SupportPeerId.swift @@ -0,0 +1,37 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + + +public func supportPeerId(account:Account) -> Signal { + return account.network.request(Api.functions.help.getSupport()) + |> map(Optional.init) + |> `catch` { _ in + return Signal.single(nil) + } + |> mapToSignal { support -> Signal in + if let support = support { + switch support { + case let .support(phoneNumber: _, user: user): + let user = TelegramUser(user: user) + return account.postbox.transaction { transaction -> PeerId in + updatePeers(transaction: transaction, peers: [user], update: { (previous, updated) -> Peer? in + return updated + }) + return user.id + } + } + } + return .single(nil) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeAppLogEventsOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeAppLogEventsOperation.swift new file mode 100644 index 0000000000..268c5e5d91 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeAppLogEventsOperation.swift @@ -0,0 +1,102 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +private enum SynchronizeAppLogEventsOperationContentType: Int32 { + case add + case sync +} + +enum SynchronizeAppLogEventsOperationContent: PostboxCoding { + case add(time: Double, type: String, peerId: PeerId?, data: JSON) + case sync + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SynchronizeAppLogEventsOperationContentType.add.rawValue: + var peerId: PeerId? + if let id = decoder.decodeOptionalInt64ForKey("p") { + peerId = PeerId(id) + } + self = .add(time: decoder.decodeDoubleForKey("tm", orElse: 0.0), type: decoder.decodeStringForKey("t", orElse: ""), peerId: peerId, data: decoder.decodeObjectForKey("d", decoder: { JSON(decoder: $0) }) as! JSON) + case SynchronizeAppLogEventsOperationContentType.sync.rawValue: + self = .sync + default: + assertionFailure() + self = .sync + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .add(time, type, peerId, data): + encoder.encodeInt32(SynchronizeAppLogEventsOperationContentType.add.rawValue, forKey: "r") + encoder.encodeDouble(time, forKey: "tm") + encoder.encodeString(type, forKey: "t") + if let peerId = peerId { + encoder.encodeInt64(peerId.toInt64(), forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + encoder.encodeObject(data, forKey: "d") + case .sync: + encoder.encodeInt32(SynchronizeAppLogEventsOperationContentType.sync.rawValue, forKey: "r") + } + } +} + +final class SynchronizeAppLogEventsOperation: PostboxCoding { + let content: SynchronizeAppLogEventsOperationContent + + init(content: SynchronizeAppLogEventsOperationContent) { + self.content = content + } + + init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeAppLogEventsOperationContent(decoder: $0) }) as! SynchronizeAppLogEventsOperationContent + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +public func addAppLogEvent(postbox: Postbox, time: Double, type: String, peerId: PeerId?, data: JSON) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeAppLogEvents + let peerId = PeerId(namespace: 0, id: 0) + let _ = (postbox.transaction { transaction in + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeAppLogEventsOperation(content: .add(time: time, type: type, peerId: peerId, data: data))) + }).start() +} + +public func invokeAppLogEventsSynchronization(postbox: Postbox) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeAppLogEvents + let peerId = PeerId(namespace: 0, id: 0) + + let _ = (postbox.transaction { transaction in + var topOperation: (SynchronizeSavedStickersOperation, Int32)? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + if let operation = entry.contents as? SynchronizeSavedStickersOperation, case .sync = operation.content { + topOperation = (operation, entry.tagLocalIndex) + } + return false + }) + + if let (_, topLocalIndex) = topOperation { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeAppLogEventsOperation(content: .sync)) + }).start() +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeChatInputStateOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeChatInputStateOperation.swift new file mode 100644 index 0000000000..c00e5ffc4c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeChatInputStateOperation.swift @@ -0,0 +1,51 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +final class SynchronizeChatInputStateOperation: PostboxCoding { + let previousState: SynchronizeableChatInputState? + + init(previousState: SynchronizeableChatInputState?) { + self.previousState = previousState + } + + init(decoder: PostboxDecoder) { + self.previousState = decoder.decodeObjectForKey("p", decoder: { SynchronizeableChatInputState(decoder: $0) }) as? SynchronizeableChatInputState + } + + func encode(_ encoder: PostboxEncoder) { + if let previousState = self.previousState { + encoder.encodeObject(previousState, forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + } +} + +func addSynchronizeChatInputStateOperation(transaction: Transaction, peerId: PeerId) { + var updateLocalIndex: Int32? + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeChatInputStates + + var previousOperation: SynchronizeChatInputStateOperation? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + updateLocalIndex = entry.tagLocalIndex + if let operation = entry.contents as? SynchronizeChatInputStateOperation { + previousOperation = operation + } + return false + }) + var previousState: SynchronizeableChatInputState? + if let previousOperation = previousOperation { + previousState = previousOperation.previousState + } else if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState { + previousState = peerChatInterfaceState.synchronizeableInputState + } + let operationContents = SynchronizeChatInputStateOperation(previousState: previousState) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeConsumeMessageContentsOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeConsumeMessageContentsOperation.swift new file mode 100644 index 0000000000..23c3bf7943 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeConsumeMessageContentsOperation.swift @@ -0,0 +1,39 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +final class SynchronizeConsumeMessageContentsOperation: PostboxCoding { + let messageIds: [MessageId] + + init(messageIds: [MessageId]) { + self.messageIds = messageIds + } + + init(decoder: PostboxDecoder) { + self.messageIds = MessageId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("i")!) + } + + func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + MessageId.encodeArrayToBuffer(self.messageIds, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "i") + } +} + +func addSynchronizeConsumeMessageContentsOperation(transaction: Transaction, messageIds: [MessageId]) { + for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(messageIds)) { + var updateLocalIndex: Int32? + /*transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, { entry in + updateLocalIndex = entry.tagLocalIndex + return false + })*/ + let operationContents = SynchronizeConsumeMessageContentsOperation(messageIds: messageIds) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) + } +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeEmojiKeywordsOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeEmojiKeywordsOperation.swift new file mode 100644 index 0000000000..3b15084071 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeEmojiKeywordsOperation.swift @@ -0,0 +1,55 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +final class SynchronizeEmojiKeywordsOperation: PostboxCoding { + let inputLanguageCode: String + let languageCode: String? + let fromVersion: Int32? + + init(inputLanguageCode: String, languageCode: String?, fromVersion: Int32?) { + self.inputLanguageCode = inputLanguageCode + self.languageCode = languageCode + self.fromVersion = fromVersion + } + + init(decoder: PostboxDecoder) { + self.inputLanguageCode = decoder.decodeStringForKey("ilc", orElse: "") + self.languageCode = decoder.decodeOptionalStringForKey("lc") + self.fromVersion = decoder.decodeOptionalInt32ForKey("v") + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.inputLanguageCode, forKey: "ilc") + if let languageCode = self.languageCode { + encoder.encodeString(languageCode, forKey: "lc") + } else { + encoder.encodeNil(forKey: "lc") + } + if let fromVersion = self.fromVersion { + encoder.encodeInt32(fromVersion, forKey: "v") + } else { + encoder.encodeNil(forKey: "v") + } + } +} + +func addSynchronizeEmojiKeywordsOperation(transaction: Transaction, inputLanguageCode: String, languageCode: String?, fromVersion: Int32?) { + let tag = OperationLogTags.SynchronizeEmojiKeywords + let peerId = PeerId(emojiKeywordColletionIdForCode(inputLanguageCode).id) + + var hasExistingOperation = false + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag) { entry -> Bool in + hasExistingOperation = true + return false + } + + guard !hasExistingOperation else { + return + } + let operationContents = SynchronizeEmojiKeywordsOperation(inputLanguageCode: inputLanguageCode, languageCode: languageCode, fromVersion: fromVersion) + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeGroupedPeersOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeGroupedPeersOperation.swift new file mode 100644 index 0000000000..d48676c3d8 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeGroupedPeersOperation.swift @@ -0,0 +1,65 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +final class SynchronizeGroupedPeersOperation: PostboxCoding { + let peerId: PeerId + let groupId: PeerGroupId + + init(peerId: PeerId, groupId: PeerGroupId) { + self.peerId = peerId + self.groupId = groupId + } + + init(decoder: PostboxDecoder) { + self.peerId = PeerId(decoder.decodeInt64ForKey("peerId", orElse: 0)) + self.groupId = PeerGroupId.init(rawValue: decoder.decodeInt32ForKey("groupId", orElse: 0)) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.peerId.toInt64(), forKey: "peerId") + encoder.encodeInt32(self.groupId.rawValue, forKey: "groupId") + } +} + +public func updatePeerGroupIdInteractively(postbox: Postbox, peerId: PeerId, groupId: PeerGroupId) -> Signal { + return postbox.transaction { transaction -> Void in + updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: groupId) + } +} + +public func updatePeerGroupIdInteractively(transaction: Transaction, peerId: PeerId, groupId: PeerGroupId) { + let initialInclusion = transaction.getPeerChatListInclusion(peerId) + var updatedInclusion = initialInclusion + switch initialInclusion { + case .notIncluded: + break + case let .ifHasMessagesOrOneOf(currentGroupId, pinningIndex, minTimestamp): + if currentGroupId == groupId { + return + } + if pinningIndex != nil { + /*let updatedPinnedItems = transaction.getPinnedItemIds(groupId: currentGroupId).filter({ $0 != .peer(peerId) }) + transaction.setPinnedItemIds(groupId: currentGroupId, itemIds: updatedPinnedItems)*/ + } + updatedInclusion = .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: nil, minTimestamp: minTimestamp) + } + if initialInclusion != updatedInclusion { + transaction.updatePeerChatListInclusion(peerId, inclusion: updatedInclusion) + if peerId.namespace != Namespaces.Peer.SecretChat { + addSynchronizeGroupedPeersOperation(transaction: transaction, peerId: peerId, groupId: groupId) + } + } +} + +private func addSynchronizeGroupedPeersOperation(transaction: Transaction, peerId: PeerId, groupId: PeerGroupId) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeGroupedPeers + let logPeerId = PeerId(namespace: 0, id: 0) + + transaction.operationLogAddEntry(peerId: logPeerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeGroupedPeersOperation(peerId: peerId, groupId: groupId)) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeInstalledStickerPacksOperations.swift b/submodules/TelegramCore/TelegramCore/SynchronizeInstalledStickerPacksOperations.swift new file mode 100644 index 0000000000..cafe0a9b73 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeInstalledStickerPacksOperations.swift @@ -0,0 +1,141 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +enum SynchronizeInstalledStickerPacksOperationNamespace: Int32 { + case stickers = 0 + case masks = 1 +} + +final class SynchronizeInstalledStickerPacksOperation: PostboxCoding { + let previousPacks: [ItemCollectionId] + let archivedPacks: [ItemCollectionId] + + init(previousPacks: [ItemCollectionId], archivedPacks: [ItemCollectionId]) { + self.previousPacks = previousPacks + self.archivedPacks = archivedPacks + } + + init(decoder: PostboxDecoder) { + self.previousPacks = ItemCollectionId.decodeArrayFromBuffer(decoder.decodeBytesForKey("p")!) + self.archivedPacks = decoder.decodeBytesForKey("ap").flatMap(ItemCollectionId.decodeArrayFromBuffer) ?? [] + } + + func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + ItemCollectionId.encodeArrayToBuffer(self.previousPacks, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "p") + buffer.reset() + ItemCollectionId.encodeArrayToBuffer(self.archivedPacks, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "ap") + } +} + +final class SynchronizeMarkFeaturedStickerPacksAsSeenOperation: PostboxCoding { + let ids: [ItemCollectionId] + + init(ids: [ItemCollectionId]) { + self.ids = ids + } + + init(decoder: PostboxDecoder) { + self.ids = ItemCollectionId.decodeArrayFromBuffer(decoder.decodeBytesForKey("p")!) + } + + func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + ItemCollectionId.encodeArrayToBuffer(self.ids, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "p") + } +} + +public enum AddSynchronizeInstalledStickerPacksOperationContent { + case sync + case add([ItemCollectionId]) + case remove([ItemCollectionId]) + case archive([ItemCollectionId]) +} + +public func addSynchronizeInstalledStickerPacksOperation(transaction: Transaction, namespace: ItemCollectionId.Namespace, content: AddSynchronizeInstalledStickerPacksOperationContent) { + let operationNamespace: SynchronizeInstalledStickerPacksOperationNamespace + switch namespace { + case Namespaces.ItemCollection.CloudStickerPacks: + operationNamespace = .stickers + case Namespaces.ItemCollection.CloudMaskPacks: + operationNamespace = .masks + default: + return + } + addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: operationNamespace, content: content) +} + +func addSynchronizeInstalledStickerPacksOperation(transaction: Transaction, namespace: SynchronizeInstalledStickerPacksOperationNamespace, content: AddSynchronizeInstalledStickerPacksOperationContent) { + var updateLocalIndex: Int32? + let tag: PeerOperationLogTag + let itemCollectionNamespace: ItemCollectionId.Namespace + switch namespace { + case .stickers: + tag = OperationLogTags.SynchronizeInstalledStickerPacks + itemCollectionNamespace = Namespaces.ItemCollection.CloudStickerPacks + case .masks: + tag = OperationLogTags.SynchronizeInstalledMasks + itemCollectionNamespace = Namespaces.ItemCollection.CloudMaskPacks + } + var previousStickerPackIds: [ItemCollectionId]? + var archivedPacks: [ItemCollectionId] = [] + transaction.operationLogEnumerateEntries(peerId: PeerId(namespace: 0, id: 0), tag: tag, { entry in + updateLocalIndex = entry.tagLocalIndex + if let operation = entry.contents as? SynchronizeInstalledStickerPacksOperation { + previousStickerPackIds = operation.previousPacks + archivedPacks = operation.archivedPacks + } else { + assertionFailure() + } + return false + }) + let previousPacks = previousStickerPackIds ?? transaction.getItemCollectionsInfos(namespace: itemCollectionNamespace).map { $0.0 } + switch content { + case .sync: + break + case let .add(ids): + let idsSet = Set(ids) + archivedPacks = archivedPacks.filter({ !idsSet.contains($0) }) + case let .remove(ids): + let idsSet = Set(ids) + archivedPacks = archivedPacks.filter({ !idsSet.contains($0) }) + case let .archive(ids): + for id in ids { + if !archivedPacks.contains(id) { + archivedPacks.append(id) + } + } + } + let operationContents = SynchronizeInstalledStickerPacksOperation(previousPacks: previousPacks, archivedPacks: archivedPacks) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: PeerId(namespace: 0, id: 0), tag: tag, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: PeerId(namespace: 0, id: 0), tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} + +func addSynchronizeMarkFeaturedStickerPacksAsSeenOperation(transaction: Transaction, ids: [ItemCollectionId]) { + var updateLocalIndex: Int32? + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkFeaturedStickerPacksAsSeen + var previousIds = Set() + transaction.operationLogEnumerateEntries(peerId: PeerId(namespace: 0, id: 0), tag: tag, { entry in + updateLocalIndex = entry.tagLocalIndex + if let operation = entry.contents as? SynchronizeMarkFeaturedStickerPacksAsSeenOperation { + previousIds = Set(operation.ids) + } else { + assertionFailure() + } + return false + }) + let operationContents = SynchronizeMarkFeaturedStickerPacksAsSeenOperation(ids: Array(previousIds.union(Set(ids)))) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: PeerId(namespace: 0, id: 0), tag: tag, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: PeerId(namespace: 0, id: 0), tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeLocalizationUpdatesOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeLocalizationUpdatesOperation.swift new file mode 100644 index 0000000000..ae5ea727e7 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeLocalizationUpdatesOperation.swift @@ -0,0 +1,36 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +final class SynchronizeLocalizationUpdatesOperation: PostboxCoding { + init() { + } + + init(decoder: PostboxDecoder) { + } + + func encode(_ encoder: PostboxEncoder) { + } +} + +func addSynchronizeLocalizationUpdatesOperation(transaction: Transaction) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeLocalizationUpdates + let peerId = PeerId(namespace: 0, id: 0) + + var topLocalIndex: Int32? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + topLocalIndex = entry.tagLocalIndex + return false + }) + + if let topLocalIndex = topLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeLocalizationUpdatesOperation()) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeMarkAllUnseenPersonalMessagesOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeMarkAllUnseenPersonalMessagesOperation.swift new file mode 100644 index 0000000000..1fa91c7a00 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeMarkAllUnseenPersonalMessagesOperation.swift @@ -0,0 +1,47 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +final class SynchronizeMarkAllUnseenPersonalMessagesOperation: PostboxCoding { + let maxId: MessageId.Id + + init(maxId: MessageId.Id) { + self.maxId = maxId + } + + init(decoder: PostboxDecoder) { + self.maxId = decoder.decodeInt32ForKey("maxId", orElse: Int32.min + 1) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.maxId, forKey: "maxId") + } +} + +func addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: Transaction, peerId: PeerId, maxId: MessageId.Id) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkAllUnseenPersonalMessages + + var topLocalIndex: Int32? + var currentMaxId: MessageId.Id? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + topLocalIndex = entry.tagLocalIndex + if let operation = entry.contents as? SynchronizeMarkAllUnseenPersonalMessagesOperation { + currentMaxId = operation.maxId + } + return false + }) + + if let topLocalIndex = topLocalIndex { + if let currentMaxId = currentMaxId, currentMaxId >= maxId { + return + } + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeMarkAllUnseenPersonalMessagesOperation(maxId: maxId)) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizePeerReadState.swift b/submodules/TelegramCore/TelegramCore/SynchronizePeerReadState.swift new file mode 100644 index 0000000000..0484613a59 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizePeerReadState.swift @@ -0,0 +1,407 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private enum VerifyReadStateError { + case Abort + case Retry +} + +private enum PeerReadStateMarker: Equatable { + case Global(Int32) + case Channel(Int32) +} + +private func inputPeer(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.loadedPeerWithId(peerId) + |> mapToSignalPromotingError { peer -> Signal in + if let inputPeer = apiInputPeer(peer) { + return .single(inputPeer) + } else { + return .fail(.Abort) + } + } |> take(1) +} + +private func inputSecretChat(postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.loadedPeerWithId(peerId) + |> mapToSignalPromotingError { peer -> Signal in + if let inputPeer = apiInputSecretChat(peer) { + return .single(inputPeer) + } else { + return .fail(.Abort) + } + } |> take(1) +} + +private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<(Int32, Int32), VerifyReadStateError> { + return inputPeer(postbox: postbox, peerId: peerId) + |> mapToSignal { inputPeer -> Signal<(Int32, Int32), VerifyReadStateError> in + return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: Int32.max, offsetDate: Int32.max, addOffset: 0, limit: 1, maxId: Int32.max, minId: 1, hash: 0)) + |> retryRequest + |> mapToSignalPromotingError { result -> Signal<(Int32, Int32), VerifyReadStateError> in + let apiMessages: [Api.Message] + switch result { + case let .channelMessages(_, _, _, messages, _, _): + apiMessages = messages + case let .messages(messages, _, _): + apiMessages = messages + case let .messagesSlice(_, _, _, messages, _, _): + apiMessages = messages + case .messagesNotModified: + apiMessages = [] + } + if let message = apiMessages.first, let timestamp = message.timestamp { + return .single((message.rawId, timestamp)) + } else { + return .fail(.Abort) + } + } + } +} + +func fetchPeerCloudReadState(network: Network, postbox: Postbox, peerId: PeerId, inputPeer: Api.InputPeer) -> Signal { + return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeer(peer: inputPeer)])) + |> map { result -> PeerReadState? in + switch result { + case let .peerDialogs(dialogs, _, _, _, _): + if let dialog = dialogs.filter({ $0.peerId == peerId }).first { + let apiTopMessage: Int32 + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiUnreadCount: Int32 + let apiMarkedUnread: Bool + switch dialog { + case let .dialog(flags, _, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, _, _, _, _, _): + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + case .dialogFolder: + assertionFailure() + return nil + } + + return .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) + } else { + return nil + } + } + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +private func dialogReadState(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<(PeerReadState, PeerReadStateMarker), VerifyReadStateError> { + return dialogTopMessage(network: network, postbox: postbox, peerId: peerId) + |> mapToSignal { topMessage -> Signal<(PeerReadState, PeerReadStateMarker), VerifyReadStateError> in + return inputPeer(postbox: postbox, peerId: peerId) + |> mapToSignal { inputPeer -> Signal<(PeerReadState, PeerReadStateMarker), VerifyReadStateError> in + return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeer(peer: inputPeer)])) + |> retryRequest + |> mapToSignalPromotingError { result -> Signal<(PeerReadState, PeerReadStateMarker), VerifyReadStateError> in + switch result { + case let .peerDialogs(dialogs, _, _, _, state): + if let dialog = dialogs.filter({ $0.peerId == peerId }).first { + let apiTopMessage: Int32 + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiUnreadCount: Int32 + let apiMarkedUnread: Bool + var apiChannelPts: Int32 = 0 + switch dialog { + case let .dialog(flags, _, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, _, _, pts, _, _): + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + if let pts = pts { + apiChannelPts = pts + } + case .dialogFolder: + assertionFailure() + return .fail(.Abort) + } + + let marker: PeerReadStateMarker + if peerId.namespace == Namespaces.Peer.CloudChannel { + marker = .Channel(apiChannelPts) + } else { + let pts: Int32 + switch state { + case let .state(statePts, _, _, _, _): + pts = statePts + } + + marker = .Global(pts) + } + + return .single((.idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread), marker)) + } else { + return .fail(.Abort) + } + } + } + } + } +} + +private func ==(lhs: PeerReadStateMarker, rhs: PeerReadStateMarker) -> Bool { + switch lhs { + case let .Global(lhsPts): + switch rhs { + case let .Global(rhsPts) where lhsPts == rhsPts: + return true + default: + return false + } + case let .Channel(lhsPts): + switch rhs { + case let .Channel(rhsPts) where lhsPts == rhsPts: + return true + default: + return false + } + } +} + +private func localReadStateMarker(transaction: Transaction, peerId: PeerId) -> PeerReadStateMarker? { + if peerId.namespace == Namespaces.Peer.CloudChannel { + if let state = transaction.getPeerChatState(peerId) as? ChannelState { + return .Channel(state.pts) + } else { + return nil + } + } else { + if let state = (transaction.getState() as? AuthorizedAccountState)?.state { + return .Global(state.pts) + } else { + return nil + } + } +} + +private func localReadStateMarker(network: Network, postbox: Postbox, peerId: PeerId) -> Signal { + return postbox.transaction { transaction -> PeerReadStateMarker? in + return localReadStateMarker(transaction: transaction, peerId: peerId) + } |> mapToSignalPromotingError { marker -> Signal in + if let marker = marker { + return .single(marker) + } else { + return .fail(.Abort) + } + } +} + +private func validatePeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Signal { + let readStateWithInitialState = localReadStateMarker(network: network, postbox: postbox, peerId: peerId) + |> mapToSignal { marker -> Signal<(PeerReadState, PeerReadStateMarker, PeerReadStateMarker), VerifyReadStateError> in + return dialogReadState(network: network, postbox: postbox, peerId: peerId) + |> map { ($0.0, marker, $0.1) } + } + + let maybeAppliedReadState = readStateWithInitialState |> mapToSignal { (readState, initialMarker, finalMarker) -> Signal in + return stateManager.addCustomOperation(postbox.transaction { transaction -> VerifyReadStateError? in + if initialMarker == finalMarker { + transaction.resetIncomingReadStates([peerId: [Namespaces.Message.Cloud: readState]]) + return nil + } else { + return .Retry + } + } + |> mapToSignalPromotingError { error -> Signal in + if let error = error { + return .fail(error) + } else { + return .complete() + } + }) + } + + return maybeAppliedReadState + |> `catch` { error -> Signal in + switch error { + case .Abort: + return .complete() + case .Retry: + return .fail(error) + } + } + |> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) +} + +private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId, readState: PeerReadState) -> Signal { + if !GlobalTelegramCoreConfiguration.readMessages { + return .single(readState) + } + + if peerId.namespace == Namespaces.Peer.SecretChat { + return inputSecretChat(postbox: postbox, peerId: peerId) + |> mapToSignal { inputPeer -> Signal in + switch readState { + case .idBased: + return .single(readState) + case let .indexBased(maxIncomingReadIndex, _, _, _): + return network.request(Api.functions.messages.readEncryptedHistory(peer: inputPeer, maxDate: maxIncomingReadIndex.timestamp)) + |> retryRequest + |> mapToSignalPromotingError { _ -> Signal in + return .single(readState) + } + } + } + } else { + return inputPeer(postbox: postbox, peerId: peerId) + |> mapToSignal { inputPeer -> Signal in + switch inputPeer { + case let .inputPeerChannel(channelId, accessHash): + switch readState { + case let .idBased(maxIncomingReadId, _, _, _, markedUnread): + var pushSignal: Signal = network.request(Api.functions.channels.readHistory(channel: Api.InputChannel.inputChannel(channelId: channelId, accessHash: accessHash), maxId: maxIncomingReadId)) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + if markedUnread { + pushSignal = pushSignal + |> then(network.request(Api.functions.messages.markDialogUnread(flags: 1 << 0, peer: .inputDialogPeer(peer: inputPeer))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + }) + } + return pushSignal + |> mapError { _ -> VerifyReadStateError in return VerifyReadStateError.Retry } + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(Signal.single(readState)) + case .indexBased: + return .single(readState) + } + + default: + switch readState { + case let .idBased(maxIncomingReadId, _, _, _, markedUnread): + var pushSignal: Signal = network.request(Api.functions.messages.readHistory(peer: inputPeer, maxId: maxIncomingReadId)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + if let result = result { + switch result { + case let .affectedMessages(pts, ptsCount): + stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } + return .complete() + } + + if markedUnread { + pushSignal = pushSignal + |> then(network.request(Api.functions.messages.markDialogUnread(flags: 1 << 0, peer: .inputDialogPeer(peer: inputPeer))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + }) + } + + return pushSignal + |> mapError { _ -> VerifyReadStateError in return VerifyReadStateError.Retry } + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(Signal.single(readState)) + case .indexBased: + return .single(readState) + } + } + } + } +} + +private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Signal { + let currentReadState = postbox.transaction { transaction -> (MessageId.Namespace, PeerReadState)? in + if let readStates = transaction.getPeerReadStates(peerId) { + for (namespace, readState) in readStates { + if namespace == Namespaces.Message.Cloud || namespace == Namespaces.Message.SecretIncoming { + return (namespace, readState) + } + } + } + return nil + } + + let pushedState = currentReadState + |> mapToSignalPromotingError { namespaceAndReadState -> Signal<(MessageId.Namespace, PeerReadState), VerifyReadStateError> in + if let (namespace, readState) = namespaceAndReadState { + return pushPeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, readState: readState) + |> map { updatedReadState -> (MessageId.Namespace, PeerReadState) in + return (namespace, updatedReadState) + } + } else { + return .complete() + } + } + + let verifiedState = pushedState + |> mapToSignal { namespaceAndReadState -> Signal in + return stateManager.addCustomOperation(postbox.transaction { transaction -> VerifyReadStateError? in + if let readStates = transaction.getPeerReadStates(peerId) { + for (namespace, currentReadState) in readStates where namespace == namespaceAndReadState.0 { + if currentReadState == namespaceAndReadState.1 { + transaction.confirmSynchronizedIncomingReadState(peerId) + return nil + } + } + return .Retry + } else { + transaction.confirmSynchronizedIncomingReadState(peerId) + return nil + } + } + |> mapToSignalPromotingError { error -> Signal in + if let error = error { + return .fail(error) + } else { + return .complete() + } + }) + } + + return verifiedState + |> `catch` { error -> Signal in + switch error { + case .Abort: + return .complete() + case .Retry: + return .fail(error) + } + } + |> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) +} + +func synchronizePeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId, push: Bool, validate: Bool) -> Signal { + var signal: Signal = .complete() + if push { + signal = signal |> then(pushPeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId)) + } + if validate { + signal = signal |> then(validatePeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId)) + } + return signal +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizePinnedChatsOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizePinnedChatsOperation.swift new file mode 100644 index 0000000000..e13339665f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizePinnedChatsOperation.swift @@ -0,0 +1,67 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private struct PreviousPeerItemId: PostboxCoding { + let id: PinnedItemId + + init(_ id: PinnedItemId) { + self.id = id + } + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_t", orElse: 0) { + case 0: + self.id = .peer(PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) + default: + preconditionFailure() + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self.id { + case let .peer(peerId): + encoder.encodeInt32(0, forKey: "_t") + encoder.encodeInt64(peerId.toInt64(), forKey: "i") + } + } +} + +final class SynchronizePinnedChatsOperation: PostboxCoding { + let previousItemIds: [PinnedItemId] + + init(previousItemIds: [PinnedItemId]) { + self.previousItemIds = previousItemIds + } + + init(decoder: PostboxDecoder) { + let wrappedIds: [PreviousPeerItemId] = decoder.decodeObjectArrayWithDecoderForKey("previousItemIds") + self.previousItemIds = wrappedIds.map { $0.id } + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.previousItemIds.map(PreviousPeerItemId.init), forKey: "previousItemIds") + } +} + +func addSynchronizePinnedChatsOperation(transaction: Transaction, groupId: PeerGroupId) { + let rawId: Int32 = groupId.rawValue + var previousItemIds = transaction.getPinnedItemIds(groupId: groupId) + var updateLocalIndex: Int32? + + transaction.operationLogEnumerateEntries(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, { entry in + updateLocalIndex = entry.tagLocalIndex + if let contents = entry.contents as? SynchronizePinnedChatsOperation { + previousItemIds = contents.previousItemIds + } + return false + }) + let operationContents = SynchronizePinnedChatsOperation(previousItemIds: previousItemIds) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeRecentlyUsedMediaOperations.swift b/submodules/TelegramCore/TelegramCore/SynchronizeRecentlyUsedMediaOperations.swift new file mode 100644 index 0000000000..f7e35283e0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeRecentlyUsedMediaOperations.swift @@ -0,0 +1,117 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +private enum SynchronizeRecentlyUsedMediaOperationContentType: Int32 { + case add + case remove + case clear + case sync +} + +enum SynchronizeRecentlyUsedMediaOperationContent: PostboxCoding { + case add(id: Int64, accessHash: Int64, fileReference: FileMediaReference?) + case remove(id: Int64, accessHash: Int64) + case clear + case sync + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SynchronizeRecentlyUsedMediaOperationContentType.add.rawValue: + self = .add(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeAnyObjectForKey("fr", decoder: { FileMediaReference(decoder: $0) }) as? FileMediaReference) + case SynchronizeRecentlyUsedMediaOperationContentType.remove.rawValue: + self = .remove(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + case SynchronizeRecentlyUsedMediaOperationContentType.clear.rawValue: + self = .clear + case SynchronizeRecentlyUsedMediaOperationContentType.sync.rawValue: + self = .sync + default: + assertionFailure() + self = .sync + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .add(id, accessHash, fileReference): + encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.add.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + if let fileReference = fileReference { + encoder.encodeObjectWithEncoder(fileReference, encoder: fileReference.encode, forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + case let .remove(id, accessHash): + encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.remove.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + case .clear: + encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.clear.rawValue, forKey: "r") + case .sync: + encoder.encodeInt32(SynchronizeRecentlyUsedMediaOperationContentType.sync.rawValue, forKey: "r") + } + } +} + +final class SynchronizeRecentlyUsedMediaOperation: PostboxCoding { + let content: SynchronizeRecentlyUsedMediaOperationContent + + init(content: SynchronizeRecentlyUsedMediaOperationContent) { + self.content = content + } + + init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeRecentlyUsedMediaOperationContent(decoder: $0) }) as! SynchronizeRecentlyUsedMediaOperationContent + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +enum RecentlyUsedMediaCategory { + case stickers +} + +func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category: RecentlyUsedMediaCategory, operation: SynchronizeRecentlyUsedMediaOperationContent) { + let tag: PeerOperationLogTag + switch category { + case .stickers: + tag = OperationLogTags.SynchronizeRecentlyUsedStickers + } + let peerId = PeerId(namespace: 0, id: 0) + + var topOperation: (SynchronizeRecentlyUsedMediaOperation, Int32)? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation { + topOperation = (operation, entry.tagLocalIndex) + } + return false + }) + + if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeRecentlyUsedMediaOperation(content: operation)) + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeRecentlyUsedMediaOperation(content: .sync)) +} + +func addRecentlyUsedSticker(transaction: Transaction, fileReference: FileMediaReference) { + if let resource = fileReference.media.resource as? CloudDocumentMediaResource { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: RecentMediaItem(fileReference.media)), removeTailIfCountExceeds: 20) + addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: fileReference)) + } +} + +public func clearRecentlyUsedStickers(transaction: Transaction) { + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, items: []) + addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .clear) +} + diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeSavedGifsOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeSavedGifsOperation.swift new file mode 100644 index 0000000000..7ddaba6b57 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeSavedGifsOperation.swift @@ -0,0 +1,110 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private enum SynchronizeSavedGifsOperationContentType: Int32 { + case add + case remove + case sync +} + +enum SynchronizeSavedGifsOperationContent: PostboxCoding { + case add(id: Int64, accessHash: Int64, fileReference: FileMediaReference?) + case remove(id: Int64, accessHash: Int64) + case sync + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SynchronizeSavedGifsOperationContentType.add.rawValue: + self = .add(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeAnyObjectForKey("fr", decoder: { FileMediaReference(decoder: $0) }) as? FileMediaReference) + case SynchronizeSavedGifsOperationContentType.remove.rawValue: + self = .remove(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + case SynchronizeSavedGifsOperationContentType.sync.rawValue: + self = .sync + default: + assertionFailure() + self = .sync + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .add(id, accessHash, fileReference): + encoder.encodeInt32(SynchronizeSavedGifsOperationContentType.add.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + if let fileReference = fileReference { + encoder.encodeObjectWithEncoder(fileReference, encoder: fileReference.encode, forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + case let .remove(id, accessHash): + encoder.encodeInt32(SynchronizeSavedGifsOperationContentType.remove.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + case .sync: + encoder.encodeInt32(SynchronizeSavedGifsOperationContentType.sync.rawValue, forKey: "r") + } + } +} + +final class SynchronizeSavedGifsOperation: PostboxCoding { + let content: SynchronizeSavedGifsOperationContent + + init(content: SynchronizeSavedGifsOperationContent) { + self.content = content + } + + init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeSavedGifsOperationContent(decoder: $0) }) as! SynchronizeSavedGifsOperationContent + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +func addSynchronizeSavedGifsOperation(transaction: Transaction, operation: SynchronizeSavedGifsOperationContent) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedGifs + let peerId = PeerId(namespace: 0, id: 0) + + var topOperation: (SynchronizeSavedGifsOperation, Int32)? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + if let operation = entry.contents as? SynchronizeSavedGifsOperation { + topOperation = (operation, entry.tagLocalIndex) + } + return false + }) + + if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeSavedGifsOperation(content: operation)) + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeSavedGifsOperation(content: .sync)) +} + +public func addSavedGif(postbox: Postbox, fileReference: FileMediaReference) -> Signal { + return postbox.transaction { transaction -> Void in + if let resource = fileReference.media.resource as? CloudDocumentMediaResource { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: RecentMediaItem(fileReference.media)), removeTailIfCountExceeds: 200) + addSynchronizeSavedGifsOperation(transaction: transaction, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: fileReference)) + } + } +} + +public func removeSavedGif(postbox: Postbox, mediaId: MediaId) -> Signal { + return postbox.transaction { transaction -> Void in + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? RecentMediaItem { + if let file = item.media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: entry.id) + addSynchronizeSavedGifsOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeSavedStickersOperation.swift b/submodules/TelegramCore/TelegramCore/SynchronizeSavedStickersOperation.swift new file mode 100644 index 0000000000..b6386038bc --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeSavedStickersOperation.swift @@ -0,0 +1,197 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private enum SynchronizeSavedStickersOperationContentType: Int32 { + case add + case remove + case sync +} + +enum SynchronizeSavedStickersOperationContent: PostboxCoding { + case add(id: Int64, accessHash: Int64, fileReference: FileMediaReference?) + case remove(id: Int64, accessHash: Int64) + case sync + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case SynchronizeSavedStickersOperationContentType.add.rawValue: + self = .add(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeAnyObjectForKey("fr", decoder: { FileMediaReference(decoder: $0) }) as? FileMediaReference) + case SynchronizeSavedStickersOperationContentType.remove.rawValue: + self = .remove(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + case SynchronizeSavedStickersOperationContentType.sync.rawValue: + self = .sync + default: + assertionFailure() + self = .sync + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .add(id, accessHash, fileReference): + encoder.encodeInt32(SynchronizeSavedStickersOperationContentType.add.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + if let fileReference = fileReference { + encoder.encodeObjectWithEncoder(fileReference, encoder: fileReference.encode, forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + case let .remove(id, accessHash): + encoder.encodeInt32(SynchronizeSavedStickersOperationContentType.remove.rawValue, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + case .sync: + encoder.encodeInt32(SynchronizeSavedStickersOperationContentType.sync.rawValue, forKey: "r") + } + } +} + +final class SynchronizeSavedStickersOperation: PostboxCoding { + let content: SynchronizeSavedStickersOperationContent + + init(content: SynchronizeSavedStickersOperationContent) { + self.content = content + } + + init(decoder: PostboxDecoder) { + self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeSavedStickersOperationContent(decoder: $0) }) as! SynchronizeSavedStickersOperationContent + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.content, forKey: "c") + } +} + +func addSynchronizeSavedStickersOperation(transaction: Transaction, operation: SynchronizeSavedStickersOperationContent) { + let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedStickers + let peerId = PeerId(namespace: 0, id: 0) + + var topOperation: (SynchronizeSavedStickersOperation, Int32)? + transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in + if let operation = entry.contents as? SynchronizeSavedStickersOperation { + topOperation = (operation, entry.tagLocalIndex) + } + return false + }) + + if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content { + let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) + } + + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeSavedStickersOperation(content: operation)) + transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeSavedStickersOperation(content: .sync)) +} + +public enum AddSavedStickerError { + case generic + case notFound +} + +public func getIsStickerSaved(transaction: Transaction, fileId: MediaId) -> Bool { + if let _ = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(fileId).rawValue) { + return true + } else{ + return false + } +} + +public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMediaFile) -> Signal { + return postbox.transaction { transaction -> Signal in + for attribute in file.attributes { + if case let .Sticker(_, maybePackReference, _) = attribute, let packReference = maybePackReference { + var fetchReference: StickerPackReference? + switch packReference { + case .name: + fetchReference = packReference + case let .id(id, _): + let items = transaction.getItemCollectionItems(collectionId: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: id)) + var found = false + inner: for item in items { + if let stickerItem = item as? StickerPackItem { + if stickerItem.file.fileId == file.fileId { + let stringRepresentations = stickerItem.getStringRepresentationsOfIndexKeys() + found = true + addSavedSticker(transaction: transaction, file: stickerItem.file, stringRepresentations: stringRepresentations) + break inner + } + } + } + if !found { + fetchReference = packReference + } + } + if let fetchReference = fetchReference { + return network.request(Api.functions.messages.getStickerSet(stickerset: fetchReference.apiInputStickerSet)) + |> mapError { _ -> AddSavedStickerError in + return .generic + } + |> mapToSignal { result -> Signal in + var stickerStringRepresentations: [String]? + switch result { + case let .stickerSet(_, packs, _): + var stringRepresentationsByFile: [MediaId: [String]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if stringRepresentationsByFile[mediaId] == nil { + stringRepresentationsByFile[mediaId] = [text] + } else { + stringRepresentationsByFile[mediaId]!.append(text) + } + } + } + } + stickerStringRepresentations = stringRepresentationsByFile[file.fileId] + } + if let stickerStringRepresentations = stickerStringRepresentations { + return postbox.transaction { transaction -> Void in + addSavedSticker(transaction: transaction, file: file, stringRepresentations: stickerStringRepresentations) + } |> mapError { _ in return AddSavedStickerError.generic } + } else { + return .fail(.notFound) + } + } + } + return .complete() + } + } + return .complete() + } |> mapError { _ in return AddSavedStickerError.generic } |> switchToLatest +} + +public func addSavedSticker(transaction: Transaction, file: TelegramMediaFile, stringRepresentations: [String]) { + if let resource = file.resource as? CloudDocumentMediaResource { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: SavedStickerItem(file: file, stringRepresentations: stringRepresentations)), removeTailIfCountExceeds: 5) + addSynchronizeSavedStickersOperation(transaction: transaction, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: .standalone(media: file))) + } +} + +public func removeSavedSticker(transaction: Transaction, mediaId: MediaId) { + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? SavedStickerItem { + if let resource = item.file.resource as? CloudDocumentMediaResource { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: entry.id) + addSynchronizeSavedStickersOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) + } + } +} + +public func removeSavedSticker(postbox: Postbox, mediaId: MediaId) -> Signal { + return postbox.transaction { transaction in + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? SavedStickerItem { + if let resource = item.file.resource as? CloudDocumentMediaResource { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: entry.id) + addSynchronizeSavedStickersOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) + } + } + } + +} diff --git a/submodules/TelegramCore/TelegramCore/SynchronizeableChatInputState.swift b/submodules/TelegramCore/TelegramCore/SynchronizeableChatInputState.swift new file mode 100644 index 0000000000..6ef8498ab9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SynchronizeableChatInputState.swift @@ -0,0 +1,67 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct SynchronizeableChatInputState: PostboxCoding, Equatable { + public let replyToMessageId: MessageId? + public let text: String + public let entities: [MessageTextEntity] + public let timestamp: Int32 + + public init(replyToMessageId: MessageId?, text: String, entities: [MessageTextEntity], timestamp: Int32) { + self.replyToMessageId = replyToMessageId + self.text = text + self.entities = entities + self.timestamp = timestamp + } + + public init(decoder: PostboxDecoder) { + self.text = decoder.decodeStringForKey("t", orElse: "") + self.entities = decoder.decodeObjectArrayWithDecoderForKey("e") + self.timestamp = decoder.decodeInt32ForKey("s", orElse: 0) + if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("m.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("m.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("m.i") { + self.replyToMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId) + } else { + self.replyToMessageId = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.text, forKey: "t") + encoder.encodeObjectArray(self.entities, forKey: "e") + encoder.encodeInt32(self.timestamp, forKey: "s") + if let replyToMessageId = self.replyToMessageId { + encoder.encodeInt64(replyToMessageId.peerId.toInt64(), forKey: "m.p") + encoder.encodeInt32(replyToMessageId.namespace, forKey: "m.n") + encoder.encodeInt32(replyToMessageId.id, forKey: "m.i") + } else { + encoder.encodeNil(forKey: "m.p") + encoder.encodeNil(forKey: "m.n") + encoder.encodeNil(forKey: "m.i") + } + } + + public static func ==(lhs: SynchronizeableChatInputState, rhs: SynchronizeableChatInputState) -> Bool { + if lhs.replyToMessageId != rhs.replyToMessageId { + return false + } + if lhs.text != rhs.text { + return false + } + if lhs.entities != rhs.entities { + return false + } + if lhs.timestamp != rhs.timestamp { + return false + } + return true + } +} + +public protocol SynchronizeableChatInterfaceState: PeerChatInterfaceState { + var synchronizeableInputState: SynchronizeableChatInputState? { get } + func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> SynchronizeableChatInterfaceState +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramChannel.swift b/submodules/TelegramCore/TelegramCore/TelegramChannel.swift new file mode 100644 index 0000000000..2b2326c650 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramChannel.swift @@ -0,0 +1,419 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum TelegramChannelParticipationStatus { + case member + case left + case kicked + + fileprivate var rawValue: Int32 { + switch self { + case .member: + return 0 + case .left: + return 1 + case .kicked: + return 2 + } + } + + fileprivate init(rawValue: Int32) { + switch rawValue { + case 0: + self = .member + case 1: + self = .left + case 2: + self = .kicked + default: + self = .left + } + } +} + +public struct TelegramChannelBroadcastFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let messagesShouldHaveSignatures = TelegramChannelBroadcastFlags(rawValue: 1 << 0) + public static let hasDiscussionGroup = TelegramChannelBroadcastFlags(rawValue: 1 << 1) + +} + +public struct TelegramChannelBroadcastInfo: Equatable { + public let flags: TelegramChannelBroadcastFlags + public init(flags: TelegramChannelBroadcastFlags) { + self.flags = flags + } + + public static func ==(lhs: TelegramChannelBroadcastInfo, rhs: TelegramChannelBroadcastInfo) -> Bool { + return lhs.flags == rhs.flags + } +} + +public struct TelegramChannelGroupFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } +} + +public struct TelegramChannelGroupInfo: Equatable { + public let flags: TelegramChannelGroupFlags + + public init(flags: TelegramChannelGroupFlags) { + self.flags = flags + } + + public static func ==(lhs: TelegramChannelGroupInfo, rhs: TelegramChannelGroupInfo) -> Bool { + return lhs.flags == rhs.flags + } +} + +public enum TelegramChannelInfo: Equatable { + case broadcast(TelegramChannelBroadcastInfo) + case group(TelegramChannelGroupInfo) + + public static func ==(lhs: TelegramChannelInfo, rhs: TelegramChannelInfo) -> Bool { + switch lhs { + case let .broadcast(lhsInfo): + switch rhs { + case .broadcast(lhsInfo): + return true + default: + return false + } + case let .group(lhsInfo): + switch rhs { + case .group(lhsInfo): + return true + default: + return false + } + } + } + + fileprivate func encode(encoder: PostboxEncoder) { + switch self { + case let .broadcast(info): + encoder.encodeInt32(0, forKey: "i.t") + encoder.encodeInt32(info.flags.rawValue, forKey: "i.f") + case let .group(info): + encoder.encodeInt32(1, forKey: "i.t") + encoder.encodeInt32(info.flags.rawValue, forKey: "i.f") + } + } + + fileprivate static func decode(decoder: PostboxDecoder) -> TelegramChannelInfo { + let type: Int32 = decoder.decodeInt32ForKey("i.t", orElse: 0) + if type == 0 { + return .broadcast(TelegramChannelBroadcastInfo(flags: TelegramChannelBroadcastFlags(rawValue: decoder.decodeInt32ForKey("i.f", orElse: 0)))) + } else { + return .group(TelegramChannelGroupInfo(flags: TelegramChannelGroupFlags(rawValue: decoder.decodeInt32ForKey("i.f", orElse: 0)))) + } + } +} + +public struct TelegramChannelFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let isVerified = TelegramChannelFlags(rawValue: 1 << 0) + public static let isCreator = TelegramChannelFlags(rawValue: 1 << 1) + public static let isScam = TelegramChannelFlags(rawValue: 1 << 2) +} + +public final class TelegramChannel: Peer { + public let id: PeerId + public let accessHash: Int64? + public let title: String + public let username: String? + public let photo: [TelegramMediaImageRepresentation] + public let creationDate: Int32 + public let version: Int32 + public let participationStatus: TelegramChannelParticipationStatus + public let info: TelegramChannelInfo + public let flags: TelegramChannelFlags + public let restrictionInfo: PeerAccessRestrictionInfo? + public let adminRights: TelegramChatAdminRights? + public let bannedRights: TelegramChatBannedRights? + public let defaultBannedRights: TelegramChatBannedRights? + + public var indexName: PeerIndexNameRepresentation { + return .title(title: self.title, addressName: self.username) + } + + public let associatedPeerId: PeerId? = nil + public let notificationSettingsPeerId: PeerId? = nil + + public init(id: PeerId, accessHash: Int64?, title: String, username: String?, photo: [TelegramMediaImageRepresentation], creationDate: Int32, version: Int32, participationStatus: TelegramChannelParticipationStatus, info: TelegramChannelInfo, flags: TelegramChannelFlags, restrictionInfo: PeerAccessRestrictionInfo?, adminRights: TelegramChatAdminRights?, bannedRights: TelegramChatBannedRights?, defaultBannedRights: TelegramChatBannedRights?) { + self.id = id + self.accessHash = accessHash + self.title = title + self.username = username + self.photo = photo + self.creationDate = creationDate + self.version = version + self.participationStatus = participationStatus + self.info = info + self.flags = flags + self.restrictionInfo = restrictionInfo + self.adminRights = adminRights + self.bannedRights = bannedRights + self.defaultBannedRights = defaultBannedRights + } + + public init(decoder: PostboxDecoder) { + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.accessHash = decoder.decodeOptionalInt64ForKey("ah") + self.title = decoder.decodeStringForKey("t", orElse: "") + self.username = decoder.decodeOptionalStringForKey("un") + self.photo = decoder.decodeObjectArrayForKey("ph") + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.version = decoder.decodeInt32ForKey("v", orElse: 0) + self.participationStatus = TelegramChannelParticipationStatus(rawValue: decoder.decodeInt32ForKey("ps", orElse: 0)) + self.info = TelegramChannelInfo.decode(decoder: decoder) + self.flags = TelegramChannelFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0)) + self.restrictionInfo = decoder.decodeObjectForKey("ri") as? PeerAccessRestrictionInfo + self.adminRights = decoder.decodeObjectForKey("ar", decoder: { TelegramChatAdminRights(decoder: $0) }) as? TelegramChatAdminRights + self.bannedRights = decoder.decodeObjectForKey("br", decoder: { TelegramChatBannedRights(decoder: $0) }) as? TelegramChatBannedRights + self.defaultBannedRights = decoder.decodeObjectForKey("dbr", decoder: { TelegramChatBannedRights(decoder: $0) }) as? TelegramChatBannedRights + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id.toInt64(), forKey: "i") + if let accessHash = self.accessHash { + encoder.encodeInt64(accessHash, forKey: "ah") + } else { + encoder.encodeNil(forKey: "ah") + } + encoder.encodeString(self.title, forKey: "t") + if let username = self.username { + encoder.encodeString(username, forKey: "un") + } else { + encoder.encodeNil(forKey: "un") + } + encoder.encodeObjectArray(self.photo, forKey: "ph") + encoder.encodeInt32(self.creationDate, forKey: "d") + encoder.encodeInt32(self.version, forKey: "v") + encoder.encodeInt32(self.participationStatus.rawValue, forKey: "ps") + self.info.encode(encoder: encoder) + encoder.encodeInt32(self.flags.rawValue, forKey: "fl") + if let restrictionInfo = self.restrictionInfo { + encoder.encodeObject(restrictionInfo, forKey: "ri") + } else { + encoder.encodeNil(forKey: "ri") + } + if let adminRights = self.adminRights { + encoder.encodeObject(adminRights, forKey: "ar") + } else { + encoder.encodeNil(forKey: "ar") + } + if let bannedRights = self.bannedRights { + encoder.encodeObject(bannedRights, forKey: "br") + } else { + encoder.encodeNil(forKey: "br") + } + if let defaultBannedRights = self.defaultBannedRights { + encoder.encodeObject(defaultBannedRights, forKey: "dbr") + } else { + encoder.encodeNil(forKey: "dbr") + } + } + + public func isEqual(_ other: Peer) -> Bool { + guard let other = other as? TelegramChannel else { + return false + } + + if self.id != other.id || self.accessHash != other.accessHash || self.title != other.title || self.username != other.username || self.photo != other.photo { + return false + } + + if self.creationDate != other.creationDate || self.version != other.version || self.participationStatus != other.participationStatus { + return false + } + + if self.info != other.info || self.flags != other.flags || self.restrictionInfo != other.restrictionInfo { + return false + } + + if self.adminRights != other.adminRights { + return false + } + + if self.bannedRights != other.bannedRights { + return false + } + + if self.defaultBannedRights != other.defaultBannedRights { + return false + } + + return true + } + + func withUpdatedAddressName(_ addressName: String?) -> TelegramChannel { + return TelegramChannel(id: self.id, accessHash: self.accessHash, title: self.title, username: addressName, photo: self.photo, creationDate: self.creationDate, version: self.version, participationStatus: self.participationStatus, info: self.info, flags: self.flags, restrictionInfo: self.restrictionInfo, adminRights: self.adminRights, bannedRights: self.bannedRights, defaultBannedRights: self.defaultBannedRights) + } + + func withUpdatedDefaultBannedRights(_ defaultBannedRights: TelegramChatBannedRights?) -> TelegramChannel { + return TelegramChannel(id: self.id, accessHash: self.accessHash, title: self.title, username: self.addressName, photo: self.photo, creationDate: self.creationDate, version: self.version, participationStatus: self.participationStatus, info: self.info, flags: self.flags, restrictionInfo: self.restrictionInfo, adminRights: self.adminRights, bannedRights: self.bannedRights, defaultBannedRights: defaultBannedRights) + } +} + +public enum TelegramChannelPermission { + case sendMessages + case pinMessages + case inviteMembers + case editAllMessages + case deleteAllMessages + case banMembers + case addAdmins + case changeInfo +} + +public extension TelegramChannel { + public func hasPermission(_ permission: TelegramChannelPermission) -> Bool { + if self.flags.contains(.isCreator) { + return true + } + switch permission { + case .sendMessages: + if case .broadcast = self.info { + if let adminRights = self.adminRights { + return adminRights.flags.contains(.canPostMessages) + } else { + return false + } + } else { + if let adminRights = self.adminRights, adminRights.flags.contains(.canPostMessages) { + return true + } + if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendMessages) { + return false + } + if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendMessages) { + return false + } + return true + } + case .pinMessages: + if case .broadcast = self.info { + if let adminRights = self.adminRights { + return adminRights.flags.contains(.canPinMessages) || adminRights.flags.contains(.canEditMessages) + } else { + return false + } + } else { + if let adminRights = self.adminRights, adminRights.flags.contains(.canPinMessages) { + return true + } + if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banPinMessages) { + return false + } + if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banPinMessages) { + return false + } + return true + } + case .inviteMembers: + if case .broadcast = self.info { + if let adminRights = self.adminRights { + return adminRights.flags.contains(.canInviteUsers) + } else { + return false + } + } else { + if let adminRights = self.adminRights, adminRights.flags.contains(.canInviteUsers) { + return true + } + if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banAddMembers) { + return false + } + if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banAddMembers) { + return false + } + return true + } + case .editAllMessages: + if let adminRights = self.adminRights, adminRights.flags.contains(.canEditMessages) { + return true + } + return false + case .deleteAllMessages: + if let adminRights = self.adminRights, adminRights.flags.contains(.canDeleteMessages) { + return true + } + return false + case .banMembers: + if let adminRights = self.adminRights, adminRights.flags.contains(.canBanUsers) { + return true + } + return false + case .changeInfo: + if case .broadcast = self.info { + if let adminRights = self.adminRights { + return adminRights.flags.contains(.canChangeInfo) + } else { + return false + } + } else { + if let adminRights = self.adminRights, adminRights.flags.contains(.canChangeInfo) { + return true + } + if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banChangeInfo) { + return false + } + if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banChangeInfo) { + return false + } + return true + } + case .addAdmins: + if let adminRights = self.adminRights, adminRights.flags.contains(.canAddAdmins) { + return true + } + return false + } + } + + public func hasBannedPermission(_ rights: TelegramChatBannedRightsFlags) -> (Int32, Bool)? { + if self.flags.contains(.isCreator) { + return nil + } + if let adminRights = self.adminRights, !adminRights.flags.isEmpty { + return nil + } + if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(rights) { + return (Int32.max, false) + } + if let bannedRights = self.bannedRights, bannedRights.flags.contains(rights) { + return (bannedRights.untilDate, true) + } + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramChannelAdminRights.swift b/submodules/TelegramCore/TelegramCore/TelegramChannelAdminRights.swift new file mode 100644 index 0000000000..a10db19a95 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramChannelAdminRights.swift @@ -0,0 +1,99 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct TelegramChatAdminRightsFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let canChangeInfo = TelegramChatAdminRightsFlags(rawValue: 1 << 0) + public static let canPostMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 1) + public static let canEditMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 2) + public static let canDeleteMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 3) + public static let canBanUsers = TelegramChatAdminRightsFlags(rawValue: 1 << 4) + public static let canInviteUsers = TelegramChatAdminRightsFlags(rawValue: 1 << 5) + public static let canPinMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 7) + public static let canAddAdmins = TelegramChatAdminRightsFlags(rawValue: 1 << 9) + + public static var groupSpecific: TelegramChatAdminRightsFlags = [ + .canChangeInfo, + .canDeleteMessages, + .canBanUsers, + .canInviteUsers, + .canPinMessages, + .canAddAdmins + ] + + public static var broadcastSpecific: TelegramChatAdminRightsFlags = [ + .canChangeInfo, + .canPostMessages, + .canEditMessages, + .canDeleteMessages, + .canInviteUsers, + .canAddAdmins + ] + + public var count: Int { + var result = 0 + var index = 0 + while index < 31 { + let currentValue = self.rawValue >> Int32(index) + index += 1 + if currentValue == 0 { + break + } + + if (currentValue & 1) != 0 { + result += 1 + } + } + return result + } +} + +public struct TelegramChatAdminRights: PostboxCoding, Equatable { + public let flags: TelegramChatAdminRightsFlags + + public init(flags: TelegramChatAdminRightsFlags) { + self.flags = flags + } + + public init(decoder: PostboxDecoder) { + self.flags = TelegramChatAdminRightsFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + } + + public static func ==(lhs: TelegramChatAdminRights, rhs: TelegramChatAdminRights) -> Bool { + return lhs.flags == rhs.flags + } + + public var isEmpty: Bool { + return self.flags.isEmpty + } +} + +extension TelegramChatAdminRights { + init(apiAdminRights: Api.ChatAdminRights) { + switch apiAdminRights { + case let .chatAdminRights(flags): + self.init(flags: TelegramChatAdminRightsFlags(rawValue: flags)) + } + } + + var apiAdminRights: Api.ChatAdminRights { + return .chatAdminRights(flags: self.flags.rawValue) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramChannelBannedRights.swift b/submodules/TelegramCore/TelegramCore/TelegramChannelBannedRights.swift new file mode 100644 index 0000000000..3d8a11b329 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramChannelBannedRights.swift @@ -0,0 +1,68 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct TelegramChatBannedRightsFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let banReadMessages = TelegramChatBannedRightsFlags(rawValue: 1 << 0) + public static let banSendMessages = TelegramChatBannedRightsFlags(rawValue: 1 << 1) + public static let banSendMedia = TelegramChatBannedRightsFlags(rawValue: 1 << 2) + public static let banSendStickers = TelegramChatBannedRightsFlags(rawValue: 1 << 3) + public static let banSendGifs = TelegramChatBannedRightsFlags(rawValue: 1 << 4) + public static let banSendGames = TelegramChatBannedRightsFlags(rawValue: 1 << 5) + public static let banSendInline = TelegramChatBannedRightsFlags(rawValue: 1 << 6) + public static let banEmbedLinks = TelegramChatBannedRightsFlags(rawValue: 1 << 7) + public static let banSendPolls = TelegramChatBannedRightsFlags(rawValue: 1 << 8) + public static let banChangeInfo = TelegramChatBannedRightsFlags(rawValue: 1 << 10) + public static let banAddMembers = TelegramChatBannedRightsFlags(rawValue: 1 << 15) + public static let banPinMessages = TelegramChatBannedRightsFlags(rawValue: 1 << 17) +} + +public struct TelegramChatBannedRights: PostboxCoding, Equatable { + public let flags: TelegramChatBannedRightsFlags + public let untilDate: Int32 + + public init(flags: TelegramChatBannedRightsFlags, untilDate: Int32) { + self.flags = flags + self.untilDate = untilDate + } + + public init(decoder: PostboxDecoder) { + self.flags = TelegramChatBannedRightsFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.untilDate = decoder.decodeInt32ForKey("d", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + encoder.encodeInt32(self.untilDate, forKey: "d") + } + + public static func ==(lhs: TelegramChatBannedRights, rhs: TelegramChatBannedRights) -> Bool { + return lhs.flags == rhs.flags && lhs.untilDate == rhs.untilDate + } +} + +extension TelegramChatBannedRights { + init(apiBannedRights: Api.ChatBannedRights) { + switch apiBannedRights { + case let .chatBannedRights(flags, untilDate): + self.init(flags: TelegramChatBannedRightsFlags(rawValue: flags), untilDate: untilDate) + } + } + + var apiBannedRights: Api.ChatBannedRights { + return .chatBannedRights(flags: self.flags.rawValue, untilDate: self.untilDate) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramCore.h b/submodules/TelegramCore/TelegramCore/TelegramCore.h new file mode 100644 index 0000000000..7431adb663 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramCore.h @@ -0,0 +1,17 @@ +// +// TelegramCore.h +// TelegramCore +// +// Created by Peter on 8/1/16. +// Copyright © 2016 Peter. All rights reserved. +// + +#import + +//! Project version number for TelegramCore. +FOUNDATION_EXPORT double TelegramCoreVersionNumber; + +//! Project version string for TelegramCore. +FOUNDATION_EXPORT const unsigned char TelegramCoreVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import diff --git a/submodules/TelegramCore/TelegramCore/TelegramCoreIncludes.h b/submodules/TelegramCore/TelegramCore/TelegramCoreIncludes.h new file mode 100644 index 0000000000..214f0b11aa --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramCoreIncludes.h @@ -0,0 +1,7 @@ +#ifndef TelegramCoreIncludes_h +#define TelegramCoreIncludes_h + +#import "Crypto.h" +#import "Reachability.h" + +#endif diff --git a/submodules/TelegramCore/TelegramCore/TelegramCorePrivate/module.modulemap b/submodules/TelegramCore/TelegramCore/TelegramCorePrivate/module.modulemap new file mode 100644 index 0000000000..043192a38f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramCorePrivate/module.modulemap @@ -0,0 +1,8 @@ +module TelegramCorePrivateModule { + header "../../third-party/libphonenumber-iOS/NBPhoneNumber.h" + header "../../third-party/libphonenumber-iOS/NBPhoneNumberUtil.h" + header "../../third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h" + header "../NetworkLogging.h" + header "../MonotonicTime.h" + header "../TelegramCoreIncludes.h" +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramDeviceContactImportInfo.swift b/submodules/TelegramCore/TelegramCore/TelegramDeviceContactImportInfo.swift new file mode 100644 index 0000000000..7fd96046b9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramDeviceContactImportInfo.swift @@ -0,0 +1,99 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +private let phoneNumberKeyPrefix: ValueBoxKey = { + let result = ValueBoxKey(length: 1) + result.setInt8(0, value: 0) + return result +}() + +enum TelegramDeviceContactImportIdentifier: Hashable, Comparable, Equatable { + case phoneNumber(DeviceContactNormalizedPhoneNumber) + + init?(key: ValueBoxKey) { + if key.length < 2 { + return nil + } + switch key.getInt8(0) { + case 0: + guard let string = key.substringValue(1 ..< key.length) else { + return nil + } + self = .phoneNumber(DeviceContactNormalizedPhoneNumber(rawValue: string)) + default: + return nil + } + } + + var key: ValueBoxKey { + switch self { + case let .phoneNumber(number): + + let numberKey = ValueBoxKey(number.rawValue) + return phoneNumberKeyPrefix + numberKey + } + } + + static func <(lhs: TelegramDeviceContactImportIdentifier, rhs: TelegramDeviceContactImportIdentifier) -> Bool { + switch lhs { + case let .phoneNumber(lhsNumber): + switch rhs { + case let .phoneNumber(rhsNumber): + return lhsNumber.rawValue < rhsNumber.rawValue + } + } + } +} + +enum TelegramDeviceContactImportedData: PostboxCoding { + case imported(data: ImportableDeviceContactData, importedByCount: Int32) + case retryLater + + init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_t", orElse: 0) { + case 0: + self = .imported(data: decoder.decodeObjectForKey("d", decoder: { ImportableDeviceContactData(decoder: $0) }) as! ImportableDeviceContactData, importedByCount: decoder.decodeInt32ForKey("c", orElse: 0)) + case 1: + self = .retryLater + default: + assertionFailure() + self = .retryLater + } + } + + func encode(_ encoder: PostboxEncoder) { + switch self { + case let .imported(data, importedByCount): + encoder.encodeInt32(0, forKey: "_t") + encoder.encodeObject(data, forKey: "d") + encoder.encodeInt32(importedByCount, forKey: "c") + case .retryLater: + encoder.encodeInt32(1, forKey: "_t") + } + } +} + +public func deviceContactsImportedByCount(postbox: Postbox, contacts: [(String, [DeviceContactNormalizedPhoneNumber])]) -> Signal<[String: Int32], NoError> { + return postbox.transaction { transaction -> [String: Int32] in + var result: [String: Int32] = [:] + for (id, numbers) in contacts { + var maxCount: Int32 = 0 + for number in numbers { + if let value = transaction.getDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(number).key) as? TelegramDeviceContactImportedData, case let .imported(imported) = value { + + maxCount = max(maxCount, imported.importedByCount) + } + } + if maxCount != 0 { + result[id] = maxCount + } + } + return result + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramGroup.swift b/submodules/TelegramCore/TelegramCore/TelegramGroup.swift new file mode 100644 index 0000000000..16c1899da3 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramGroup.swift @@ -0,0 +1,215 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum TelegramGroupRole: Equatable, PostboxCoding { + case creator + case admin(TelegramChatAdminRights) + case member + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_v", orElse: 0) { + case 0: + self = .creator + case 1: + self = .admin(decoder.decodeObjectForKey("r", decoder: { TelegramChatAdminRights(decoder: $0) }) as! TelegramChatAdminRights) + case 2: + self = .member + default: + assertionFailure() + self = .member + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .creator: + encoder.encodeInt32(0, forKey: "_v") + case let .admin(rights): + encoder.encodeInt32(1, forKey: "_v") + encoder.encodeObject(rights, forKey: "r") + case .member: + encoder.encodeInt32(2, forKey: "_v") + } + } +} + +public enum TelegramGroupMembership: Int32 { + case Member + case Left + case Removed +} + +public struct TelegramGroupFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let deactivated = TelegramGroupFlags(rawValue: 1 << 1) +} + +public struct TelegramGroupToChannelMigrationReference: Equatable { + public let peerId: PeerId + public let accessHash: Int64 + + public static func ==(lhs: TelegramGroupToChannelMigrationReference, rhs: TelegramGroupToChannelMigrationReference) -> Bool { + return lhs.peerId == rhs.peerId && lhs.accessHash == rhs.accessHash + } +} + +public final class TelegramGroup: Peer { + public let id: PeerId + public let title: String + public let photo: [TelegramMediaImageRepresentation] + public let participantCount: Int + public let role: TelegramGroupRole + public let membership: TelegramGroupMembership + public let flags: TelegramGroupFlags + public let defaultBannedRights: TelegramChatBannedRights? + public let migrationReference: TelegramGroupToChannelMigrationReference? + public let creationDate: Int32 + public let version: Int + + public var indexName: PeerIndexNameRepresentation { + return .title(title: self.title, addressName: nil) + } + + public let associatedPeerId: PeerId? = nil + public let notificationSettingsPeerId: PeerId? = nil + + public init(id: PeerId, title: String, photo: [TelegramMediaImageRepresentation], participantCount: Int, role: TelegramGroupRole, membership: TelegramGroupMembership, flags: TelegramGroupFlags, defaultBannedRights: TelegramChatBannedRights?, migrationReference: TelegramGroupToChannelMigrationReference?, creationDate: Int32, version: Int) { + self.id = id + self.title = title + self.photo = photo + self.participantCount = participantCount + self.role = role + self.membership = membership + self.flags = flags + self.defaultBannedRights = defaultBannedRights + self.migrationReference = migrationReference + self.creationDate = creationDate + self.version = version + } + + public init(decoder: PostboxDecoder) { + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.title = decoder.decodeStringForKey("t", orElse: "") + self.photo = decoder.decodeObjectArrayForKey("ph") + self.participantCount = Int(decoder.decodeInt32ForKey("pc", orElse: 0)) + if let role = decoder.decodeObjectForKey("rv", decoder: { TelegramGroupRole(decoder: $0) }) as? TelegramGroupRole { + self.role = role + } else if let roleValue = decoder.decodeOptionalInt32ForKey("r"), roleValue == 0 { + self.role = .creator + } else { + self.role = .member + } + self.membership = TelegramGroupMembership(rawValue: decoder.decodeInt32ForKey("m", orElse: 0))! + self.flags = TelegramGroupFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.defaultBannedRights = decoder.decodeObjectForKey("dbr", decoder: { TelegramChatBannedRights(decoder: $0) }) as? TelegramChatBannedRights + let migrationPeerId: Int64? = decoder.decodeOptionalInt64ForKey("mr.i") + let migrationAccessHash: Int64? = decoder.decodeOptionalInt64ForKey("mr.a") + if let migrationPeerId = migrationPeerId, let migrationAccessHash = migrationAccessHash { + self.migrationReference = TelegramGroupToChannelMigrationReference(peerId: PeerId(migrationPeerId), accessHash: migrationAccessHash) + } else { + self.migrationReference = nil + } + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id.toInt64(), forKey: "i") + encoder.encodeString(self.title, forKey: "t") + encoder.encodeObjectArray(self.photo, forKey: "ph") + encoder.encodeInt32(Int32(self.participantCount), forKey: "pc") + encoder.encodeObject(self.role, forKey: "rv") + encoder.encodeInt32(self.membership.rawValue, forKey: "m") + if let defaultBannedRights = self.defaultBannedRights { + encoder.encodeObject(defaultBannedRights, forKey: "dbr") + } else { + encoder.encodeNil(forKey: "dbr") + } + if let migrationReference = self.migrationReference { + encoder.encodeInt64(migrationReference.peerId.toInt64(), forKey: "mr.i") + encoder.encodeInt64(migrationReference.accessHash, forKey: "mr.a") + } else { + encoder.encodeNil(forKey: "mr.i") + encoder.encodeNil(forKey: "mr.a") + } + encoder.encodeInt32(self.creationDate, forKey: "d") + encoder.encodeInt32(Int32(self.version), forKey: "v") + } + + public func isEqual(_ other: Peer) -> Bool { + if let other = other as? TelegramGroup { + if self.id != other.id { + return false + } + if self.title != other.title { + return false + } + if self.photo != other.photo { + return false + } + if self.membership != other.membership { + return false + } + if self.version != other.version { + return false + } + if self.participantCount != other.participantCount { + return false + } + if self.role != other.role { + return false + } + if self.defaultBannedRights != other.defaultBannedRights { + return false + } + if self.migrationReference != other.migrationReference { + return false + } + if self.creationDate != other.creationDate { + return false + } + if self.flags != other.flags { + return false + } + return true + } else { + return false + } + } + + public func updateFlags(flags: TelegramGroupFlags, version: Int) -> TelegramGroup { + return TelegramGroup(id: self.id, title: self.title, photo: self.photo, participantCount: self.participantCount, role: self.role, membership: self.membership, flags: flags, defaultBannedRights: self.defaultBannedRights, migrationReference: self.migrationReference, creationDate: self.creationDate, version: version) + } + + public func updateDefaultBannedRights(_ defaultBannedRights: TelegramChatBannedRights?, version: Int) -> TelegramGroup { + return TelegramGroup(id: self.id, title: self.title, photo: self.photo, participantCount: self.participantCount, role: self.role, membership: self.membership, flags: self.flags, defaultBannedRights: defaultBannedRights, migrationReference: self.migrationReference, creationDate: self.creationDate, version: version) + } +} + +public extension TelegramGroup { + public func hasBannedPermission(_ rights: TelegramChatBannedRightsFlags) -> Bool { + switch self.role { + case .creator, .admin: + return false + default: + if let bannedRights = self.defaultBannedRights { + return bannedRights.flags.contains(rights) + } else { + return false + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaAction.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaAction.swift new file mode 100644 index 0000000000..a2b6e07029 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaAction.swift @@ -0,0 +1,341 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum PhoneCallDiscardReason: Int32 { + case missed = 0 + case disconnect = 1 + case hangup = 2 + case busy = 3 +} + +public enum SentSecureValueType: Int32 { + case personalDetails = 0 + case passport = 1 + case driversLicense = 2 + case idCard = 3 + case address = 4 + case bankStatement = 5 + case utilityBill = 6 + case rentalAgreement = 7 + case phone = 8 + case email = 9 + case internalPassport = 10 + case passportRegistration = 11 + case temporaryRegistration = 12 +} + +public enum TelegramMediaActionType: PostboxCoding, Equatable { + case unknown + case groupCreated(title: String) + case addedMembers(peerIds: [PeerId]) + case removedMembers(peerIds: [PeerId]) + case photoUpdated(image: TelegramMediaImage?) + case titleUpdated(title: String) + case pinnedMessageUpdated + case joinedByLink(inviter: PeerId) + case channelMigratedFromGroup(title: String, groupId: PeerId) + case groupMigratedToChannel(channelId: PeerId) + case historyCleared + case historyScreenshot + case messageAutoremoveTimeoutUpdated(Int32) + case gameScore(gameId: Int64, score: Int32) + case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?) + case paymentSent(currency: String, totalAmount: Int64) + case customText(text: String, entities: [MessageTextEntity]) + case botDomainAccessGranted(domain: String) + case botSentSecureValues(types: [SentSecureValueType]) + case peerJoined + case phoneNumberRequest + + public init(decoder: PostboxDecoder) { + let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) + switch rawValue { + case 1: + self = .groupCreated(title: decoder.decodeStringForKey("title", orElse: "")) + case 2: + self = .addedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!)) + case 3: + self = .removedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!)) + case 4: + self = .photoUpdated(image: decoder.decodeObjectForKey("image") as? TelegramMediaImage) + case 5: + self = .titleUpdated(title: decoder.decodeStringForKey("title", orElse: "")) + case 6: + self = .pinnedMessageUpdated + case 7: + self = .joinedByLink(inviter: PeerId(decoder.decodeInt64ForKey("inviter", orElse: 0))) + case 8: + self = .channelMigratedFromGroup(title: decoder.decodeStringForKey("title", orElse: ""), groupId: PeerId(decoder.decodeInt64ForKey("groupId", orElse: 0))) + case 9: + self = .groupMigratedToChannel(channelId: PeerId(decoder.decodeInt64ForKey("channelId", orElse: 0))) + case 10: + self = .historyCleared + case 11: + self = .historyScreenshot + case 12: + self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t", orElse: 0)) + case 13: + self = .gameScore(gameId: decoder.decodeInt64ForKey("i", orElse: 0), score: decoder.decodeInt32ForKey("s", orElse: 0)) + case 14: + var discardReason: PhoneCallDiscardReason? + if let value = decoder.decodeOptionalInt32ForKey("dr") { + discardReason = PhoneCallDiscardReason(rawValue: value) + } + self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0)) + case 15: + self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0)) + case 16: + self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent")) + case 17: + self = .botDomainAccessGranted(domain: decoder.decodeStringForKey("do", orElse: "")) + case 18: + self = .botSentSecureValues(types: decoder.decodeInt32ArrayForKey("ty").map { value -> SentSecureValueType in + return SentSecureValueType(rawValue: value) ?? .personalDetails + }) + case 19: + self = .peerJoined + case 20: + self = .phoneNumberRequest + default: + self = .unknown + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .unknown: + break + case let .groupCreated(title): + encoder.encodeInt32(1, forKey: "_rawValue") + encoder.encodeString(title, forKey: "title") + case let .addedMembers(peerIds): + encoder.encodeInt32(2, forKey: "_rawValue") + let buffer = WriteBuffer() + PeerId.encodeArrayToBuffer(peerIds, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "peerIds") + case let .removedMembers(peerIds): + encoder.encodeInt32(3, forKey: "_rawValue") + let buffer = WriteBuffer() + PeerId.encodeArrayToBuffer(peerIds, buffer: buffer) + encoder.encodeBytes(buffer, forKey: "peerIds") + case let .photoUpdated(image): + encoder.encodeInt32(4, forKey: "_rawValue") + if let image = image { + encoder.encodeObject(image, forKey: "image") + } + case let .titleUpdated(title): + encoder.encodeInt32(5, forKey: "_rawValue") + encoder.encodeString(title, forKey: "title") + case .pinnedMessageUpdated: + encoder.encodeInt32(6, forKey: "_rawValue") + case let .joinedByLink(inviter): + encoder.encodeInt32(7, forKey: "_rawValue") + encoder.encodeInt64(inviter.toInt64(), forKey: "inviter") + case let .channelMigratedFromGroup(title, groupId): + encoder.encodeInt32(8, forKey: "_rawValue") + encoder.encodeString(title, forKey: "title") + encoder.encodeInt64(groupId.toInt64(), forKey: "groupId") + case let .groupMigratedToChannel(channelId): + encoder.encodeInt32(9, forKey: "_rawValue") + encoder.encodeInt64(channelId.toInt64(), forKey: "channelId") + case .historyCleared: + encoder.encodeInt32(10, forKey: "_rawValue") + case .historyScreenshot: + encoder.encodeInt32(11, forKey: "_rawValue") + case let .messageAutoremoveTimeoutUpdated(timeout): + encoder.encodeInt32(12, forKey: "_rawValue") + encoder.encodeInt32(timeout, forKey: "t") + case let .gameScore(gameId, score): + encoder.encodeInt32(13, forKey: "_rawValue") + encoder.encodeInt64(gameId, forKey: "i") + encoder.encodeInt32(score, forKey: "s") + case let .paymentSent(currency, totalAmount): + encoder.encodeInt32(15, forKey: "_rawValue") + encoder.encodeString(currency, forKey: "currency") + encoder.encodeInt64(totalAmount, forKey: "ta") + case let .phoneCall(callId, discardReason, duration): + encoder.encodeInt32(14, forKey: "_rawValue") + encoder.encodeInt64(callId, forKey: "i") + if let discardReason = discardReason { + encoder.encodeInt32(discardReason.rawValue, forKey: "dr") + } else { + encoder.encodeNil(forKey: "dr") + } + if let duration = duration { + encoder.encodeInt32(duration, forKey: "d") + } else { + encoder.encodeNil(forKey: "d") + } + case let .customText(text, entities): + encoder.encodeInt32(16, forKey: "_rawValue") + encoder.encodeString(text, forKey: "text") + encoder.encodeObjectArray(entities, forKey: "ent") + case let .botDomainAccessGranted(domain): + encoder.encodeInt32(17, forKey: "_rawValue") + encoder.encodeString(domain, forKey: "do") + case let .botSentSecureValues(types): + encoder.encodeInt32(18, forKey: "_rawValue") + encoder.encodeInt32Array(types.map { $0.rawValue }, forKey: "ty") + case .peerJoined: + encoder.encodeInt32(19, forKey: "_rawValue") + case .phoneNumberRequest: + encoder.encodeInt32(20, forKey: "_rawValue") + } + } + + public var peerIds: [PeerId] { + switch self { + case let .addedMembers(peerIds): + return peerIds + case let .removedMembers(peerIds): + return peerIds + case let .joinedByLink(inviter): + return [inviter] + case let .channelMigratedFromGroup(_, groupId): + return [groupId] + case let .groupMigratedToChannel(channelId): + return [channelId] + default: + return [] + } + } +} + +public final class TelegramMediaAction: Media { + public let id: MediaId? = nil + public var peerIds: [PeerId] { + return self.action.peerIds + } + + public let action: TelegramMediaActionType + + public init(action: TelegramMediaActionType) { + self.action = action + } + + public init(decoder: PostboxDecoder) { + self.action = TelegramMediaActionType(decoder: decoder) + } + + public func encode(_ encoder: PostboxEncoder) { + self.action.encode(encoder) + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaAction { + return self.action == other.action + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} + +func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMediaAction? { + switch action { + case let .messageActionChannelCreate(title): + return TelegramMediaAction(action: .groupCreated(title: title)) + case let .messageActionChannelMigrateFrom(title, chatId): + return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))) + case let .messageActionChatAddUser(users): + return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: $0) }))) + case let .messageActionChatCreate(title, _): + return TelegramMediaAction(action: .groupCreated(title: title)) + case .messageActionChatDeletePhoto: + return TelegramMediaAction(action: .photoUpdated(image: nil)) + case let .messageActionChatDeleteUser(userId): + return TelegramMediaAction(action: .removedMembers(peerIds: [PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)])) + case let .messageActionChatEditPhoto(photo): + return TelegramMediaAction(action: .photoUpdated(image: telegramMediaImageFromApiPhoto(photo))) + case let .messageActionChatEditTitle(title): + return TelegramMediaAction(action: .titleUpdated(title: title)) + case let .messageActionChatJoinedByLink(inviterId): + return TelegramMediaAction(action: .joinedByLink(inviter: PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId))) + case let .messageActionChatMigrateTo(channelId): + return TelegramMediaAction(action: .groupMigratedToChannel(channelId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId))) + case .messageActionHistoryClear: + return TelegramMediaAction(action: .historyCleared) + case .messageActionPinMessage: + return TelegramMediaAction(action: .pinnedMessageUpdated) + case let .messageActionGameScore(gameId, score): + return TelegramMediaAction(action: .gameScore(gameId: gameId, score: score)) + case let .messageActionPhoneCall(_, callId, reason, duration): + var discardReason: PhoneCallDiscardReason? + if let reason = reason { + discardReason = PhoneCallDiscardReason(apiReason: reason) + } + return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration)) + case .messageActionEmpty: + return nil + case let .messageActionPaymentSent(currency, totalAmount): + return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount)) + case .messageActionPaymentSentMe: + return nil + case .messageActionScreenshotTaken: + return TelegramMediaAction(action: .historyScreenshot) + case let .messageActionCustomAction(message): + return TelegramMediaAction(action: .customText(text: message, entities: [])) + case let .messageActionBotAllowed(domain): + return TelegramMediaAction(action: .botDomainAccessGranted(domain: domain)) + case .messageActionSecureValuesSentMe: + return nil + case let .messageActionSecureValuesSent(types): + return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init))) + case .messageActionContactSignUp: + return TelegramMediaAction(action: .peerJoined) + } +} + +extension PhoneCallDiscardReason { + init(apiReason: Api.PhoneCallDiscardReason) { + switch apiReason { + case .phoneCallDiscardReasonBusy: + self = .busy + case .phoneCallDiscardReasonDisconnect: + self = .disconnect + case .phoneCallDiscardReasonHangup: + self = .hangup + case .phoneCallDiscardReasonMissed: + self = .missed + } + } +} + +extension SentSecureValueType { + init(apiType: Api.SecureValueType) { + switch apiType { + case .secureValueTypePersonalDetails: + self = .personalDetails + case .secureValueTypePassport: + self = .passport + case .secureValueTypeDriverLicense: + self = .driversLicense + case .secureValueTypeIdentityCard: + self = .idCard + case .secureValueTypeAddress: + self = .address + case .secureValueTypeBankStatement: + self = .bankStatement + case .secureValueTypeUtilityBill: + self = .utilityBill + case .secureValueTypeRentalAgreement: + self = .rentalAgreement + case .secureValueTypePhone: + self = .phone + case .secureValueTypeEmail: + self = .email + case .secureValueTypeInternalPassport: + self = .internalPassport + case .secureValueTypePassportRegistration: + self = .passportRegistration + case .secureValueTypeTemporaryRegistration: + self = .temporaryRegistration + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaContact.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaContact.swift new file mode 100644 index 0000000000..b444f5e238 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaContact.swift @@ -0,0 +1,71 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class TelegramMediaContact: Media { + public let id: MediaId? = nil + public let firstName: String + public let lastName: String + public let phoneNumber: String + public let peerId: PeerId? + public let vCardData: String? + + public let peerIds: [PeerId] + + public init(firstName: String, lastName: String, phoneNumber: String, peerId: PeerId?, vCardData: String?) { + self.firstName = firstName + self.lastName = lastName + self.phoneNumber = phoneNumber + self.peerId = peerId + self.vCardData = vCardData + if let peerId = peerId { + self.peerIds = [peerId] + } else { + self.peerIds = [] + } + } + + public init(decoder: PostboxDecoder) { + self.firstName = decoder.decodeStringForKey("n.f", orElse: "") + self.lastName = decoder.decodeStringForKey("n.l", orElse: "") + self.phoneNumber = decoder.decodeStringForKey("pn", orElse: "") + if let peerIdValue = decoder.decodeOptionalInt64ForKey("p") { + self.peerId = PeerId(peerIdValue) + self.peerIds = [PeerId(peerIdValue)] + } else { + self.peerId = nil + self.peerIds = [] + } + self.vCardData = decoder.decodeOptionalStringForKey("vc") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.firstName, forKey: "n.f") + encoder.encodeString(self.lastName, forKey: "n.l") + encoder.encodeString(self.phoneNumber, forKey: "pn") + if let peerId = self.peerId { + encoder.encodeInt64(peerId.toInt64(), forKey: "p") + } + if let vCardData = self.vCardData { + encoder.encodeString(vCardData, forKey: "vc") + } else { + encoder.encodeNil(forKey: "vc") + } + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaContact { + if self.id == other.id && self.firstName == other.firstName && self.lastName == other.lastName && self.phoneNumber == other.phoneNumber && self.peerId == other.peerId && self.vCardData == other.vCardData && self.peerIds == other.peerIds { + return true + } + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaExpiredContent.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaExpiredContent.swift new file mode 100644 index 0000000000..dc90b36be9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaExpiredContent.swift @@ -0,0 +1,42 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum TelegramMediaExpiredContentData: Int32 { + case image + case file +} + +public final class TelegramMediaExpiredContent: Media { + public let data: TelegramMediaExpiredContentData + + public let id: MediaId? = nil + public let peerIds: [PeerId] = [] + + public init(data: TelegramMediaExpiredContentData) { + self.data = data + } + + public init(decoder: PostboxDecoder) { + self.data = TelegramMediaExpiredContentData(rawValue: decoder.decodeInt32ForKey("d", orElse: 0))! + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.data.rawValue, forKey: "d") + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaExpiredContent { + return self.data == other.data + } else { + return false + } + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift new file mode 100644 index 0000000000..0cd49735ad --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift @@ -0,0 +1,592 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +private let typeFileName: Int32 = 0 +private let typeSticker: Int32 = 1 +private let typeImageSize: Int32 = 2 +private let typeAnimated: Int32 = 3 +private let typeVideo: Int32 = 4 +private let typeAudio: Int32 = 5 +private let typeHasLinkedStickers: Int32 = 6 + +public enum StickerPackReference: PostboxCoding, Hashable, Equatable { + case id(id: Int64, accessHash: Int64) + case name(String) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("r", orElse: 0) { + case 0: + self = .id(id: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0)) + case 1: + self = .name(decoder.decodeStringForKey("n", orElse: "")) + default: + self = .name("") + assertionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .id(id, accessHash): + encoder.encodeInt32(0, forKey: "r") + encoder.encodeInt64(id, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + case let .name(name): + encoder.encodeInt32(1, forKey: "r") + encoder.encodeString(name, forKey: "n") + } + } + + public static func ==(lhs: StickerPackReference, rhs: StickerPackReference) -> Bool { + switch lhs { + case let .id(id, accessHash): + if case .id(id, accessHash) = rhs { + return true + } else { + return false + } + case let .name(name): + if case .name(name) = rhs { + return true + } else { + return false + } + } + } +} + +public struct TelegramMediaVideoFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let instantRoundVideo = TelegramMediaVideoFlags(rawValue: 1 << 0) + public static let supportsStreaming = TelegramMediaVideoFlags(rawValue: 1 << 1) +} + +public struct StickerMaskCoords: PostboxCoding { + public let n: Int32 + public let x: Double + public let y: Double + public let zoom: Double + + public init(n: Int32, x: Double, y: Double, zoom: Double) { + self.n = n + self.x = x + self.y = y + self.zoom = zoom + } + + public init(decoder: PostboxDecoder) { + self.n = decoder.decodeInt32ForKey("n", orElse: 0) + self.x = decoder.decodeDoubleForKey("x", orElse: 0.0) + self.y = decoder.decodeDoubleForKey("y", orElse: 0.0) + self.zoom = decoder.decodeDoubleForKey("z", orElse: 0.0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.n, forKey: "n") + encoder.encodeDouble(self.x, forKey: "x") + encoder.encodeDouble(self.y, forKey: "y") + encoder.encodeDouble(self.zoom, forKey: "z") + } +} + +public enum TelegramMediaFileAttribute: PostboxCoding { + case FileName(fileName: String) + case Sticker(displayText: String, packReference: StickerPackReference?, maskData: StickerMaskCoords?) + case ImageSize(size: CGSize) + case Animated + case Video(duration: Int, size: CGSize, flags: TelegramMediaVideoFlags) + case Audio(isVoice: Bool, duration: Int, title: String?, performer: String?, waveform: MemoryBuffer?) + case HasLinkedStickers + + public init(decoder: PostboxDecoder) { + let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0) + switch type { + case typeFileName: + self = .FileName(fileName: decoder.decodeStringForKey("fn", orElse: "")) + case typeSticker: + self = .Sticker(displayText: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference, maskData: decoder.decodeObjectForKey("mc", decoder: { StickerMaskCoords(decoder: $0) }) as? StickerMaskCoords) + case typeImageSize: + self = .ImageSize(size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("h", orElse: 0)))) + case typeAnimated: + self = .Animated + case typeVideo: + self = .Video(duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), size: CGSize(width: CGFloat(decoder.decodeInt32ForKey("w", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("h", orElse: 0))), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0))) + case typeAudio: + let waveformBuffer = decoder.decodeBytesForKeyNoCopy("wf") + var waveform: MemoryBuffer? + if let waveformBuffer = waveformBuffer { + waveform = MemoryBuffer(copyOf: waveformBuffer) + } + self = .Audio(isVoice: decoder.decodeInt32ForKey("iv", orElse: 0) != 0, duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), title: decoder.decodeOptionalStringForKey("ti"), performer: decoder.decodeOptionalStringForKey("pe"), waveform: waveform) + case typeHasLinkedStickers: + self = .HasLinkedStickers + default: + preconditionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .FileName(fileName): + encoder.encodeInt32(typeFileName, forKey: "t") + encoder.encodeString(fileName, forKey: "fn") + case let .Sticker(displayText, packReference, maskCoords): + encoder.encodeInt32(typeSticker, forKey: "t") + encoder.encodeString(displayText, forKey: "dt") + if let packReference = packReference { + encoder.encodeObject(packReference, forKey: "pr") + } else { + encoder.encodeNil(forKey: "pr") + } + if let maskCoords = maskCoords { + encoder.encodeObject(maskCoords, forKey: "mc") + } else { + encoder.encodeNil(forKey: "mc") + } + case let .ImageSize(size): + encoder.encodeInt32(typeImageSize, forKey: "t") + encoder.encodeInt32(Int32(size.width), forKey: "w") + encoder.encodeInt32(Int32(size.height), forKey: "h") + case .Animated: + encoder.encodeInt32(typeAnimated, forKey: "t") + case let .Video(duration, size, flags): + encoder.encodeInt32(typeVideo, forKey: "t") + encoder.encodeInt32(Int32(duration), forKey: "du") + encoder.encodeInt32(Int32(size.width), forKey: "w") + encoder.encodeInt32(Int32(size.height), forKey: "h") + encoder.encodeInt32(flags.rawValue, forKey: "f") + case let .Audio(isVoice, duration, title, performer, waveform): + encoder.encodeInt32(typeAudio, forKey: "t") + encoder.encodeInt32(isVoice ? 1 : 0, forKey: "iv") + encoder.encodeInt32(Int32(duration), forKey: "du") + if let title = title { + encoder.encodeString(title, forKey: "ti") + } + if let performer = performer { + encoder.encodeString(performer, forKey: "pe") + } + if let waveform = waveform { + encoder.encodeBytes(waveform, forKey: "wf") + } + case .HasLinkedStickers: + encoder.encodeInt32(typeHasLinkedStickers, forKey: "t") + } + } +} + +func dimensionsForFileAttributes(_ attributes: [TelegramMediaFileAttribute]) -> CGSize? { + for attribute in attributes { + switch attribute { + case let .Video(_, size, _): + return size + case let .ImageSize(size): + return size + default: + break + } + } + return nil +} + +func durationForFileAttributes(_ attributes: [TelegramMediaFileAttribute]) -> Int32? { + for attribute in attributes { + switch attribute { + case let .Video(duration, _, _): + return Int32(duration) + case let .Audio(_, duration, _, _, _): + return Int32(duration) + default: + break + } + } + return nil +} + +public enum TelegramMediaFileReference: PostboxCoding, Equatable { + case cloud(fileId: Int64, accessHash: Int64, fileReference: Data?) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_v", orElse: 0) { + case 0: + self = .cloud(fileId: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeBytesForKey("fr")?.makeData()) + default: + self = .cloud(fileId: 0, accessHash: 0, fileReference: nil) + assertionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .cloud(imageId, accessHash, fileReference): + encoder.encodeInt32(0, forKey: "_v") + encoder.encodeInt64(imageId, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + if let fileReference = fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + } + } +} + +public final class TelegramMediaFile: Media, Equatable { + public let fileId: MediaId + public let partialReference: PartialMediaReference? + public let resource: TelegramMediaResource + public let previewRepresentations: [TelegramMediaImageRepresentation] + public let immediateThumbnailData: Data? + public let mimeType: String + public let size: Int? + public let attributes: [TelegramMediaFileAttribute] + public let peerIds: [PeerId] = [] + + public var id: MediaId? { + return self.fileId + } + + public init(fileId: MediaId, partialReference: PartialMediaReference?, resource: TelegramMediaResource, previewRepresentations: [TelegramMediaImageRepresentation], immediateThumbnailData: Data?, mimeType: String, size: Int?, attributes: [TelegramMediaFileAttribute]) { + self.fileId = fileId + self.partialReference = partialReference + self.resource = resource + self.previewRepresentations = previewRepresentations + self.immediateThumbnailData = immediateThumbnailData + self.mimeType = mimeType + self.size = size + self.attributes = attributes + } + + public init(decoder: PostboxDecoder) { + self.fileId = MediaId(decoder.decodeBytesForKeyNoCopy("i")!) + self.partialReference = decoder.decodeAnyObjectForKey("prf", decoder: { PartialMediaReference(decoder: $0) }) as? PartialMediaReference + self.resource = decoder.decodeObjectForKey("r") as? TelegramMediaResource ?? EmptyMediaResource() + self.previewRepresentations = decoder.decodeObjectArrayForKey("pr") + self.immediateThumbnailData = decoder.decodeDataForKey("itd") + self.mimeType = decoder.decodeStringForKey("mt", orElse: "") + if let size = decoder.decodeOptionalInt32ForKey("s") { + self.size = Int(size) + } else { + self.size = nil + } + self.attributes = decoder.decodeObjectArrayForKey("at") + } + + public func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + self.fileId.encodeToBuffer(buffer) + encoder.encodeBytes(buffer, forKey: "i") + if let partialReference = self.partialReference { + encoder.encodeObjectWithEncoder(partialReference, encoder: partialReference.encode, forKey: "prf") + } else { + encoder.encodeNil(forKey: "prf") + } + encoder.encodeObject(self.resource, forKey: "r") + encoder.encodeObjectArray(self.previewRepresentations, forKey: "pr") + if let immediateThumbnailData = self.immediateThumbnailData { + encoder.encodeData(immediateThumbnailData, forKey: "itd") + } else { + encoder.encodeNil(forKey: "itd") + } + encoder.encodeString(self.mimeType, forKey: "mt") + if let size = self.size { + encoder.encodeInt32(Int32(size), forKey: "s") + } else { + encoder.encodeNil(forKey: "s") + } + encoder.encodeObjectArray(self.attributes, forKey: "at") + } + + public var fileName: String? { + get { + for attribute in self.attributes { + switch attribute { + case let .FileName(fileName): + return fileName + case _: + break + } + } + return nil + } + } + + public var isSticker: Bool { + for attribute in self.attributes { + if case .Sticker = attribute { + return true + } + } + return false + } + + public var isVideo: Bool { + for attribute in self.attributes { + if case .Video = attribute { + return true + } + } + return false + } + + public var isInstantVideo: Bool { + for attribute in self.attributes { + if case .Video(_, _, let flags) = attribute { + return flags.contains(.instantRoundVideo) + } + } + return false + } + + public var isAnimated: Bool { + for attribute in self.attributes { + if case .Animated = attribute { + return true + } + } + return false + } + + public var isMusic: Bool { + for attribute in self.attributes { + if case .Audio(false, _, _, _, _) = attribute { + return true + } + } + return false + } + + public var isVoice: Bool { + for attribute in self.attributes { + if case .Audio(true, _, _, _, _) = attribute { + return true + } + } + return false + } + + public var dimensions: CGSize? { + return dimensionsForFileAttributes(self.attributes) + } + + public var duration: Int32? { + return durationForFileAttributes(self.attributes) + } + + public func isEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaFile else { + return false + } + + if self.fileId != other.fileId { + return false + } + + if self.partialReference != other.partialReference { + return false + } + + if !self.resource.isEqual(to: other.resource) { + return false + } + + if self.previewRepresentations != other.previewRepresentations { + return false + } + + if self.immediateThumbnailData != other.immediateThumbnailData { + return false + } + + if self.size != other.size { + return false + } + + if self.mimeType != other.mimeType { + return false + } + + return true + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaFile else { + return false + } + + if self.fileId != other.fileId { + return false + } + + if self.partialReference != other.partialReference { + return false + } + + if !self.resource.id.isEqual(to: other.resource.id) { + return false + } + + if self.previewRepresentations.count != other.previewRepresentations.count { + return false + } + + for i in 0 ..< self.previewRepresentations.count { + if !self.previewRepresentations[i].isSemanticallyEqual(to: other.previewRepresentations[i]) { + return false + } + } + + if self.immediateThumbnailData != other.immediateThumbnailData { + return false + } + + if self.size != other.size { + return false + } + + if self.mimeType != other.mimeType { + return false + } + + return true + } + + public func withUpdatedPartialReference(_ partialReference: PartialMediaReference?) -> TelegramMediaFile { + return TelegramMediaFile(fileId: self.fileId, partialReference: partialReference, resource: self.resource, previewRepresentations: self.previewRepresentations, immediateThumbnailData: self.immediateThumbnailData, mimeType: self.mimeType, size: self.size, attributes: self.attributes) + } + + public func withUpdatedSize(_ size: Int?) -> TelegramMediaFile { + return TelegramMediaFile(fileId: self.fileId, partialReference: self.partialReference, resource: self.resource, previewRepresentations: self.previewRepresentations, immediateThumbnailData: self.immediateThumbnailData, mimeType: self.mimeType, size: size, attributes: self.attributes) + } + + public func withUpdatedPreviewRepresentations(_ previewRepresentations: [TelegramMediaImageRepresentation]) -> TelegramMediaFile { + return TelegramMediaFile(fileId: self.fileId, partialReference: self.partialReference, resource: self.resource, previewRepresentations: previewRepresentations, immediateThumbnailData: self.immediateThumbnailData, mimeType: self.mimeType, size: self.size, attributes: self.attributes) + } + + public func withUpdatedAttributes(_ attributes: [TelegramMediaFileAttribute]) -> TelegramMediaFile { + return TelegramMediaFile(fileId: self.fileId, partialReference: self.partialReference, resource: self.resource, previewRepresentations: self.previewRepresentations, immediateThumbnailData: self.immediateThumbnailData, mimeType: self.mimeType, size: self.size, attributes: attributes) + } +} + +public func ==(lhs: TelegramMediaFile, rhs: TelegramMediaFile) -> Bool { + return lhs.isEqual(to: rhs) +} + +extension StickerPackReference { + init?(apiInputSet: Api.InputStickerSet) { + switch apiInputSet { + case .inputStickerSetEmpty: + return nil + case let .inputStickerSetID(id, accessHash): + self = .id(id: id, accessHash: accessHash) + case let .inputStickerSetShortName(shortName): + self = .name(shortName) + } + } +} + +extension StickerMaskCoords { + init(apiMaskCoords: Api.MaskCoords) { + switch apiMaskCoords { + case let .maskCoords(n, x, y, zoom): + self.init(n: n, x: x, y: y, zoom: zoom) + } + } +} + +func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAttribute]) -> [TelegramMediaFileAttribute] { + var result: [TelegramMediaFileAttribute] = [] + for attribute in attributes { + switch attribute { + case let .documentAttributeFilename(fileName): + result.append(.FileName(fileName: fileName)) + case let .documentAttributeSticker(_, alt, stickerSet, maskCoords): + result.append(.Sticker(displayText: alt, packReference: StickerPackReference(apiInputSet: stickerSet), maskData: maskCoords.flatMap(StickerMaskCoords.init))) + case .documentAttributeHasStickers: + result.append(.HasLinkedStickers) + case let .documentAttributeImageSize(w, h): + result.append(.ImageSize(size: CGSize(width: CGFloat(w), height: CGFloat(h)))) + case .documentAttributeAnimated: + result.append(.Animated) + case let .documentAttributeVideo(flags, duration, w, h): + var videoFlags = TelegramMediaVideoFlags() + if (flags & (1 << 0)) != 0 { + videoFlags.insert(.instantRoundVideo) + } + if (flags & (1 << 1)) != 0 { + videoFlags.insert(.supportsStreaming) + } + result.append(.Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h)), flags: videoFlags)) + case let .documentAttributeAudio(flags, duration, title, performer, waveform): + let isVoice = (flags & (1 << 10)) != 0 + var waveformBuffer: MemoryBuffer? + if let waveform = waveform { + let memory = malloc(waveform.size)! + memcpy(memory, waveform.data, waveform.size) + waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) + } + result.append(.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer)) + } + } + return result +} + +public func fileNameFromFileAttributes(_ attributes: [TelegramMediaFileAttribute]) -> String? { + for attribute in attributes { + if case let .FileName(value) = attribute { + return value + } + } + return nil +} + +func telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: Int32, documentId: Int64, accessHash: Int64, fileReference: Data?, sizes: [Api.PhotoSize]) -> (immediateThumbnail: Data?, representations: [TelegramMediaImageRepresentation]) { + var immediateThumbnailData: Data? + var representations: [TelegramMediaImageRepresentation] = [] + for size in sizes { + switch size { + case let .photoCachedSize(type, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudDocumentSizeMediaResource(datacenterId: datacenterId, documentId: documentId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + } + case let .photoSize(type, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudDocumentSizeMediaResource(datacenterId: datacenterId, documentId: documentId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + } + case let .photoStrippedSize(_, data): + immediateThumbnailData = data.makeData() + case .photoSizeEmpty: + break + } + } + return (immediateThumbnailData, representations) +} + +func telegramMediaFileFromApiDocument(_ document: Api.Document) -> TelegramMediaFile? { + switch document { + case let .document(_, id, accessHash, fileReference, _, mimeType, size, thumbs, dcId, attributes): + let parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes) + let (immediateThumbnail, previewRepresentations) = telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: dcId, documentId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: thumbs ?? []) + + return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: Int(size), fileReference: fileReference.makeData(), fileName: fileNameFromFileAttributes(parsedAttributes)), previewRepresentations: previewRepresentations, immediateThumbnailData: immediateThumbnail, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) + case .documentEmpty: + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaGame.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaGame.swift new file mode 100644 index 0000000000..3ccabcacd0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaGame.swift @@ -0,0 +1,120 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class TelegramMediaGame: Media { + public let gameId: Int64 + public let accessHash: Int64 + public let name: String + public let title: String + public let description: String + public let image: TelegramMediaImage? + public let file: TelegramMediaFile? + + public var id: MediaId? { + return MediaId(namespace: Namespaces.Media.CloudGame, id: self.gameId) + } + public let peerIds: [PeerId] = [] + + init(gameId: Int64, accessHash: Int64, name: String, title: String, description: String, image: TelegramMediaImage?, file: TelegramMediaFile?) { + self.gameId = gameId + self.accessHash = accessHash + self.name = name + self.title = title + self.description = description + self.image = image + self.file = file + } + + public init(decoder: PostboxDecoder) { + self.gameId = decoder.decodeInt64ForKey("i", orElse: 0) + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.name = decoder.decodeStringForKey("n", orElse: "") + self.title = decoder.decodeStringForKey("t", orElse: "") + self.description = decoder.decodeStringForKey("d", orElse: "") + self.image = decoder.decodeObjectForKey("p") as? TelegramMediaImage + self.file = decoder.decodeObjectForKey("f") as? TelegramMediaFile + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.gameId, forKey: "i") + encoder.encodeInt64(self.accessHash, forKey: "h") + encoder.encodeString(self.name, forKey: "n") + encoder.encodeString(self.title, forKey: "t") + encoder.encodeString(self.description, forKey: "d") + if let image = self.image { + encoder.encodeObject(image, forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + if let file = self.file { + encoder.encodeObject(file, forKey: "f") + } else { + encoder.encodeNil(forKey: "f") + } + } + + public func isEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaGame else { + return false + } + + if self.gameId != other.gameId { + return false + } + + if self.accessHash != other.accessHash { + return false + } + + if self.name != other.name { + return false + } + + if self.title != other.title { + return false + } + + if self.description != other.description { + return false + } + + if let lhsImage = self.image, let rhsImage = other.image { + if !lhsImage.isEqual(to: rhsImage) { + return false + } + } else if (self.image != nil) != (other.image != nil) { + return false + } + + if let lhsFile = self.file, let rhsFile = other.file { + if !lhsFile.isEqual(to: rhsFile) { + return false + } + } else if (self.file != nil) != (other.file != nil) { + return false + } + + return true + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} + +extension TelegramMediaGame { + convenience init(apiGame: Api.Game) { + switch apiGame { + case let .game(_, id, accessHash, shortName, title, description, photo, document): + var file: TelegramMediaFile? + if let document = document { + file = telegramMediaFileFromApiDocument(document) + } + self.init(gameId: id, accessHash: accessHash, name: shortName, title: title, description: description, image: telegramMediaImageFromApiPhoto(photo), file: file) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaImage.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaImage.swift new file mode 100644 index 0000000000..3efa00e2fc --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaImage.swift @@ -0,0 +1,254 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public enum TelegramMediaImageReference: PostboxCoding, Equatable { + case cloud(imageId: Int64, accessHash: Int64, fileReference: Data?) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("_v", orElse: 0) { + case 0: + self = .cloud(imageId: decoder.decodeInt64ForKey("i", orElse: 0), accessHash: decoder.decodeInt64ForKey("h", orElse: 0), fileReference: decoder.decodeBytesForKey("fr")?.makeData()) + default: + self = .cloud(imageId: 0, accessHash: 0, fileReference: nil) + assertionFailure() + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .cloud(imageId, accessHash, fileReference): + encoder.encodeInt32(0, forKey: "_v") + encoder.encodeInt64(imageId, forKey: "i") + encoder.encodeInt64(accessHash, forKey: "h") + if let fileReference = fileReference { + encoder.encodeBytes(MemoryBuffer(data: fileReference), forKey: "fr") + } else { + encoder.encodeNil(forKey: "fr") + } + } + } + + public static func ==(lhs: TelegramMediaImageReference, rhs: TelegramMediaImageReference) -> Bool { + switch lhs { + case let .cloud(imageId, accessHash, fileReference): + if case .cloud(imageId, accessHash, fileReference) = rhs { + return true + } else { + return false + } + } + } +} + +public final class TelegramMediaImage: Media, Equatable { + public let imageId: MediaId + public let representations: [TelegramMediaImageRepresentation] + public let immediateThumbnailData: Data? + public let reference: TelegramMediaImageReference? + public let partialReference: PartialMediaReference? + public let peerIds: [PeerId] = [] + + public var id: MediaId? { + return self.imageId + } + + public init(imageId: MediaId, representations: [TelegramMediaImageRepresentation], immediateThumbnailData: Data?, reference: TelegramMediaImageReference?, partialReference: PartialMediaReference?) { + self.imageId = imageId + self.representations = representations + self.immediateThumbnailData = immediateThumbnailData + self.reference = reference + self.partialReference = partialReference + } + + public init(decoder: PostboxDecoder) { + self.imageId = MediaId(decoder.decodeBytesForKeyNoCopy("i")!) + self.representations = decoder.decodeObjectArrayForKey("r") + self.immediateThumbnailData = decoder.decodeDataForKey("itd") + self.reference = decoder.decodeObjectForKey("rf", decoder: { TelegramMediaImageReference(decoder: $0) }) as? TelegramMediaImageReference + self.partialReference = decoder.decodeAnyObjectForKey("prf", decoder: { PartialMediaReference(decoder: $0) }) as? PartialMediaReference + } + + public func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + self.imageId.encodeToBuffer(buffer) + encoder.encodeBytes(buffer, forKey: "i") + encoder.encodeObjectArray(self.representations, forKey: "r") + if let immediateThumbnailData = self.immediateThumbnailData { + encoder.encodeData(immediateThumbnailData, forKey: "itd") + } else { + encoder.encodeNil(forKey: "itd") + } + if let reference = self.reference { + encoder.encodeObject(reference, forKey: "rf") + } else { + encoder.encodeNil(forKey: "rf") + } + if let partialReference = self.partialReference { + encoder.encodeObjectWithEncoder(partialReference, encoder: partialReference.encode, forKey: "prf") + } else { + encoder.encodeNil(forKey: "prf") + } + } + + public func representationForDisplayAtSize(_ size: CGSize) -> TelegramMediaImageRepresentation? { + if self.representations.count == 0 { + return nil + } else { + var dimensions = self.representations[0].dimensions + var index = 0 + + for i in 0 ..< self.representations.count { + let representationDimensions = self.representations[i].dimensions + + if dimensions.width >= size.width - CGFloat.ulpOfOne && dimensions.height >= size.height - CGFloat.ulpOfOne { + if representationDimensions.width >= size.width && representationDimensions.height >= dimensions.height && representationDimensions.width < dimensions.width && representationDimensions.height < dimensions.height { + dimensions = representationDimensions + index = i + } + } else { + if representationDimensions.width >= dimensions.width && representationDimensions.height >= dimensions.height { + dimensions = representationDimensions + index = i + } + } + } + + return self.representations[index] + } + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaImage { + if other.imageId != self.imageId { + return false + } + if other.representations != self.representations { + return false + } + if other.immediateThumbnailData != self.immediateThumbnailData { + return false + } + if self.partialReference != other.partialReference { + return false + } + return true + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaImage { + if other.imageId != self.imageId { + return false + } + if other.representations.count != self.representations.count { + return false + } + for i in 0 ..< self.representations.count { + if !self.representations[i].isSemanticallyEqual(to: other.representations[i]) { + return false + } + } + + if self.partialReference != other.partialReference { + return false + } + return true + } + return false + } + + public static func ==(lhs: TelegramMediaImage, rhs: TelegramMediaImage) -> Bool { + return lhs.isEqual(to: rhs) + } + + public func withUpdatedPartialReference(_ partialReference: PartialMediaReference?) -> TelegramMediaImage { + return TelegramMediaImage(imageId: self.imageId, representations: self.representations, immediateThumbnailData: self.immediateThumbnailData, reference: self.reference, partialReference: partialReference) + } +} + +public final class TelegramMediaImageRepresentation: PostboxCoding, Equatable, CustomStringConvertible { + public let dimensions: CGSize + public let resource: TelegramMediaResource + + public init(dimensions: CGSize, resource: TelegramMediaResource) { + self.dimensions = dimensions + self.resource = resource + } + + public init(decoder: PostboxDecoder) { + self.dimensions = CGSize(width: CGFloat(decoder.decodeInt32ForKey("dx", orElse: 0)), height: CGFloat(decoder.decodeInt32ForKey("dy", orElse: 0))) + self.resource = decoder.decodeObjectForKey("r") as? TelegramMediaResource ?? EmptyMediaResource() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.dimensions.width), forKey: "dx") + encoder.encodeInt32(Int32(self.dimensions.height), forKey: "dy") + encoder.encodeObject(self.resource, forKey: "r") + } + + public var description: String { + return "(\(Int(dimensions.width))x\(Int(dimensions.height)))" + } + + public func isSemanticallyEqual(to other: TelegramMediaImageRepresentation) -> Bool { + if self.dimensions != other.dimensions { + return false + } + if !self.resource.id.isEqual(to: other.resource.id) { + return false + } + return true + } +} + +public func ==(lhs: TelegramMediaImageRepresentation, rhs: TelegramMediaImageRepresentation) -> Bool { + if lhs.dimensions != rhs.dimensions { + return false + } + if !lhs.resource.isEqual(to: rhs.resource) { + return false + } + return true +} + +func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId: Int64, accessHash: Int64, fileReference: Data?, sizes: [Api.PhotoSize]) -> (immediateThumbnail: Data?, representations: [TelegramMediaImageRepresentation]) { + var immediateThumbnailData: Data? + var representations: [TelegramMediaImageRepresentation] = [] + for size in sizes { + switch size { + case let .photoCachedSize(type, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + } + case let .photoSize(type, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudPhotoSizeMediaResource(datacenterId: datacenterId, photoId: photoId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(w), height: CGFloat(h)), resource: resource)) + } + case let .photoStrippedSize(_, data): + immediateThumbnailData = data.makeData() + case .photoSizeEmpty: + break + } + } + return (immediateThumbnailData, representations) +} + +func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? { + switch photo { + case let .photo(_, id, accessHash, fileReference, _, sizes, dcId): + let (immediateThumbnailData, representations) = telegramMediaImageRepresentationsFromApiSizes(datacenterId: dcId, photoId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: sizes) + return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: .cloud(imageId: id, accessHash: accessHash, fileReference: fileReference.makeData()), partialReference: nil) + case .photoEmpty: + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaInvoice.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaInvoice.swift new file mode 100644 index 0000000000..0db835780b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaInvoice.swift @@ -0,0 +1,128 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public struct TelegramMediaInvoiceFlags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public init() { + self.rawValue = 0 + } + + public static let isTest = TelegramMediaInvoiceFlags(rawValue: 1 << 0) + public static let shippingAddressRequested = TelegramMediaInvoiceFlags(rawValue: 1 << 1) +} + +public final class TelegramMediaInvoice: Media { + public var peerIds: [PeerId] = [] + + public var id: MediaId? = nil + + public let title: String + public let description: String + public let receiptMessageId: MessageId? + public let currency: String + public let totalAmount: Int64 + public let startParam: String + public let photo: TelegramMediaWebFile? + public let flags: TelegramMediaInvoiceFlags + + public init(title: String, description: String, photo: TelegramMediaWebFile?, receiptMessageId: MessageId?, currency: String, totalAmount: Int64, startParam: String, flags: TelegramMediaInvoiceFlags) { + self.title = title + self.description = description + self.photo = photo + self.receiptMessageId = receiptMessageId + self.currency = currency + self.totalAmount = totalAmount + self.startParam = startParam + self.flags = flags + } + + public init(decoder: PostboxDecoder) { + self.title = decoder.decodeStringForKey("t", orElse: "") + self.description = decoder.decodeStringForKey("d", orElse: "") + self.currency = decoder.decodeStringForKey("c", orElse: "") + self.totalAmount = decoder.decodeInt64ForKey("ta", orElse: 0) + self.startParam = decoder.decodeStringForKey("sp", orElse: "") + self.photo = decoder.decodeObjectForKey("p") as? TelegramMediaWebFile + self.flags = TelegramMediaInvoiceFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + + if let receiptMessageIdPeerId = decoder.decodeOptionalInt64ForKey("r.p") as Int64?, let receiptMessageIdNamespace = decoder.decodeOptionalInt32ForKey("r.n") as Int32?, let receiptMessageIdId = decoder.decodeOptionalInt32ForKey("r.i") as Int32? { + self.receiptMessageId = MessageId(peerId: PeerId(receiptMessageIdPeerId), namespace: receiptMessageIdNamespace, id: receiptMessageIdId) + } else { + self.receiptMessageId = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.title, forKey: "t") + encoder.encodeString(self.description, forKey: "d") + encoder.encodeString(self.currency, forKey: "c") + encoder.encodeInt64(self.totalAmount, forKey: "ta") + encoder.encodeString(self.startParam, forKey: "sp") + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + + if let photo = photo { + encoder.encodeObject(photo, forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } + + if let receiptMessageId = self.receiptMessageId { + encoder.encodeInt64(receiptMessageId.peerId.toInt64(), forKey: "r.p") + encoder.encodeInt32(receiptMessageId.namespace, forKey: "r.n") + encoder.encodeInt32(receiptMessageId.id, forKey: "r.i") + } else { + encoder.encodeNil(forKey: "r.p") + encoder.encodeNil(forKey: "r.n") + encoder.encodeNil(forKey: "r.i") + } + } + + public func isEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaInvoice else { + return false + } + + if self.title != other.title { + return false + } + + if self.description != other.description { + return false + } + + if self.currency != other.currency { + return false + } + + if self.totalAmount != other.totalAmount { + return false + } + + if self.startParam != other.startParam { + return false + } + + if self.receiptMessageId != other.receiptMessageId { + return false + } + + if self.flags != other.flags { + return false + } + + return true + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaMap.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaMap.swift new file mode 100644 index 0000000000..de78e0a4ae --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaMap.swift @@ -0,0 +1,219 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class NamedGeoPlace: PostboxCoding, Equatable { + public let country: String? + public let state: String? + public let city: String? + public let district: String? + public let street: String? + + public init(country: String?, state: String?, city: String?, district: String?, street: String?) { + self.country = country + self.state = state + self.city = city + self.district = district + self.street = street + } + + public init(decoder: PostboxDecoder) { + self.country = decoder.decodeOptionalStringForKey("gp_co") + self.state = decoder.decodeOptionalStringForKey("gp_sta") + self.city = decoder.decodeOptionalStringForKey("gp_ci") + self.district = decoder.decodeOptionalStringForKey("gp_dis") + self.street = decoder.decodeOptionalStringForKey("gp_str") + } + + public func encode(_ encoder: PostboxEncoder) { + if let country = self.country { + encoder.encodeString(country, forKey: "gp_co") + } + + if let state = self.state { + encoder.encodeString(state, forKey: "gp_sta") + } + + if let city = self.city { + encoder.encodeString(city, forKey: "gp_ci") + } + + if let district = self.district { + encoder.encodeString(district, forKey: "gp_dis") + } + + if let street = self.street { + encoder.encodeString(street, forKey: "gp_str") + } + } + + public static func ==(lhs: NamedGeoPlace, rhs: NamedGeoPlace) -> Bool { + if lhs.country != rhs.country { + return false + } + if lhs.state != rhs.state { + return false + } + if lhs.city != rhs.city { + return false + } + if lhs.district != rhs.district { + return false + } + if lhs.street != rhs.street { + return false + } + return true + } +} + +public final class MapVenue: PostboxCoding, Equatable { + public let title: String + public let address: String? + public let provider: String? + public let id: String? + public let type: String? + + public init(title: String, address: String?, provider: String?, id: String?, type: String?) { + self.title = title + self.address = address + self.provider = provider + self.id = id + self.type = type + } + + public init(decoder: PostboxDecoder) { + self.title = decoder.decodeStringForKey("ti", orElse: "") + self.address = decoder.decodeOptionalStringForKey("ad") + self.provider = decoder.decodeOptionalStringForKey("pr") + self.id = decoder.decodeOptionalStringForKey("id") + self.type = decoder.decodeOptionalStringForKey("ty") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.title, forKey: "ti") + + if let address = self.address { + encoder.encodeString(address, forKey: "ad") + } else { + encoder.encodeNil(forKey: "ad") + } + if let provider = self.provider { + encoder.encodeString(provider, forKey: "pr") + } else { + encoder.encodeNil(forKey: "pr") + } + if let id = self.id { + encoder.encodeString(id, forKey: "id") + } else { + encoder.encodeNil(forKey: "id") + } + if let type = self.type { + encoder.encodeString(type, forKey: "ty") + } else { + encoder.encodeNil(forKey: "ty") + } + } + + public static func ==(lhs: MapVenue, rhs: MapVenue) -> Bool { + if lhs.address != rhs.address { + return false + } + if lhs.provider != rhs.provider { + return false + } + if lhs.id != rhs.id { + return false + } + if lhs.type != rhs.type { + return false + } + return true + } +} + +public final class TelegramMediaMap: Media { + public let latitude: Double + public let longitude: Double + public let geoPlace: NamedGeoPlace? + public let venue: MapVenue? + public let liveBroadcastingTimeout: Int32? + + public let id: MediaId? = nil + public let peerIds: [PeerId] = [] + + public init(latitude: Double, longitude: Double, geoPlace: NamedGeoPlace?, venue: MapVenue?, liveBroadcastingTimeout: Int32?) { + self.latitude = latitude + self.longitude = longitude + self.geoPlace = geoPlace + self.venue = venue + self.liveBroadcastingTimeout = liveBroadcastingTimeout + } + + public init(decoder: PostboxDecoder) { + self.latitude = decoder.decodeDoubleForKey("la", orElse: 0.0) + self.longitude = decoder.decodeDoubleForKey("lo", orElse: 0.0) + self.geoPlace = decoder.decodeObjectForKey("gp", decoder: { NamedGeoPlace(decoder: $0) }) as? NamedGeoPlace + self.venue = decoder.decodeObjectForKey("ve", decoder: { MapVenue(decoder: $0) }) as? MapVenue + self.liveBroadcastingTimeout = decoder.decodeOptionalInt32ForKey("bt") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeDouble(self.latitude, forKey: "la") + encoder.encodeDouble(self.longitude, forKey: "lo") + if let geoPlace = self.geoPlace { + encoder.encodeObject(geoPlace, forKey: "gp") + } else { + encoder.encodeNil(forKey: "gp") + } + if let venue = self.venue { + encoder.encodeObject(venue, forKey: "ve") + } else { + encoder.encodeNil(forKey: "ve") + } + if let liveBroadcastingTimeout = self.liveBroadcastingTimeout { + encoder.encodeInt32(liveBroadcastingTimeout, forKey: "bt") + } else { + encoder.encodeNil(forKey: "bt") + } + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaMap { + if self.latitude != other.latitude || self.longitude != other.longitude { + return false + } + if self.geoPlace != other.geoPlace { + return false + } + if self.venue != other.venue { + return false + } + if self.liveBroadcastingTimeout != other.liveBroadcastingTimeout { + return false + } + return true + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} + +func telegramMediaMapFromApiGeoPoint(_ geo: Api.GeoPoint, title: String?, address: String?, provider: String?, venueId: String?, venueType: String?, liveBroadcastingTimeout: Int32?) -> TelegramMediaMap { + var venue: MapVenue? + if let title = title { + venue = MapVenue(title: title, address: address, provider: provider, id: venueId, type: venueType) + } + switch geo { + case let .geoPoint(long, lat, _): + return TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: venue, liveBroadcastingTimeout: liveBroadcastingTimeout) + case .geoPointEmpty: + return TelegramMediaMap(latitude: 0.0, longitude: 0.0, geoPlace: nil, venue: venue, liveBroadcastingTimeout: liveBroadcastingTimeout) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaPoll.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaPoll.swift new file mode 100644 index 0000000000..5af04acc90 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaPoll.swift @@ -0,0 +1,204 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public struct TelegramMediaPollOption: Equatable, PostboxCoding { + public let text: String + public let opaqueIdentifier: Data + + public init(text: String, opaqueIdentifier: Data) { + self.text = text + self.opaqueIdentifier = opaqueIdentifier + } + + public init(decoder: PostboxDecoder) { + self.text = decoder.decodeStringForKey("t", orElse: "") + self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data() + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.text, forKey: "t") + encoder.encodeData(self.opaqueIdentifier, forKey: "i") + } +} + +extension TelegramMediaPollOption { + init(apiOption: Api.PollAnswer) { + switch apiOption { + case let .pollAnswer(text, option): + self.init(text: text, opaqueIdentifier: option.makeData()) + } + } + + var apiOption: Api.PollAnswer { + return .pollAnswer(text: self.text, option: Buffer(data: self.opaqueIdentifier)) + } +} + +public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding { + public let selected: Bool + public let opaqueIdentifier: Data + public let count: Int32 + + public init(selected: Bool, opaqueIdentifier: Data, count: Int32) { + self.selected = selected + self.opaqueIdentifier = opaqueIdentifier + self.count = count + } + + public init(decoder: PostboxDecoder) { + self.selected = decoder.decodeInt32ForKey("s", orElse: 0) != 0 + self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data() + self.count = decoder.decodeInt32ForKey("c", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.selected ? 1 : 0, forKey: "s") + encoder.encodeData(self.opaqueIdentifier, forKey: "i") + encoder.encodeInt32(self.count, forKey: "c") + } +} + +extension TelegramMediaPollOptionVoters { + init(apiVoters: Api.PollAnswerVoters) { + switch apiVoters { + case let .pollAnswerVoters(flags, option, voters): + self.init(selected: (flags & (1 << 0)) != 0, opaqueIdentifier: option.makeData(), count: voters) + } + } +} + +public struct TelegramMediaPollResults: Equatable, PostboxCoding { + public let voters: [TelegramMediaPollOptionVoters]? + public let totalVoters: Int32? + + public init(voters: [TelegramMediaPollOptionVoters]?, totalVoters: Int32?) { + self.voters = voters + self.totalVoters = totalVoters + } + + public init(decoder: PostboxDecoder) { + self.voters = decoder.decodeOptionalObjectArrayWithDecoderForKey("v") + self.totalVoters = decoder.decodeOptionalInt32ForKey("t") + } + + public func encode(_ encoder: PostboxEncoder) { + if let voters = self.voters { + encoder.encodeObjectArray(voters, forKey: "v") + } else { + encoder.encodeNil(forKey: "v") + } + if let totalVoters = self.totalVoters { + encoder.encodeInt32(totalVoters, forKey: "t") + } else { + encoder.encodeNil(forKey: "t") + } + } +} + +extension TelegramMediaPollResults { + init(apiResults: Api.PollResults) { + switch apiResults { + case let .pollResults(_, results, totalVoters): + self.init(voters: results.flatMap({ $0.map(TelegramMediaPollOptionVoters.init(apiVoters:)) }), totalVoters: totalVoters) + } + } +} + +public final class TelegramMediaPoll: Media, Equatable { + public var id: MediaId? { + return self.pollId + } + public let pollId: MediaId + public let peerIds: [PeerId] = [] + + public let text: String + public let options: [TelegramMediaPollOption] + public let results: TelegramMediaPollResults + public let isClosed: Bool + + public init(pollId: MediaId, text: String, options: [TelegramMediaPollOption], results: TelegramMediaPollResults, isClosed: Bool) { + self.pollId = pollId + self.text = text + self.options = options + self.results = results + self.isClosed = isClosed + } + + public init(decoder: PostboxDecoder) { + if let idBytes = decoder.decodeBytesForKeyNoCopy("i") { + self.pollId = MediaId(idBytes) + } else { + self.pollId = MediaId(namespace: Namespaces.Media.LocalPoll, id: 0) + } + self.text = decoder.decodeStringForKey("t", orElse: "") + self.options = decoder.decodeObjectArrayWithDecoderForKey("os") + self.results = decoder.decodeObjectForKey("rs", decoder: { TelegramMediaPollResults(decoder: $0) }) as? TelegramMediaPollResults ?? TelegramMediaPollResults(voters: nil, totalVoters: nil) + self.isClosed = decoder.decodeInt32ForKey("ic", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + self.pollId.encodeToBuffer(buffer) + encoder.encodeBytes(buffer, forKey: "i") + encoder.encodeString(self.text, forKey: "t") + encoder.encodeObjectArray(self.options, forKey: "os") + encoder.encodeObject(results, forKey: "rs") + encoder.encodeInt32(self.isClosed ? 1 : 0, forKey: "ic") + } + + public func isEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaPoll else { + return false + } + return self == other + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } + + public static func ==(lhs: TelegramMediaPoll, rhs: TelegramMediaPoll) -> Bool { + if lhs.pollId != rhs.pollId { + return false + } + if lhs.text != rhs.text { + return false + } + if lhs.options != rhs.options { + return false + } + if lhs.results != rhs.results { + return false + } + if lhs.isClosed != rhs.isClosed { + return false + } + return true + } + + func withUpdatedResults(_ results: TelegramMediaPollResults, min: Bool) -> TelegramMediaPoll { + let updatedResults: TelegramMediaPollResults + if min { + if let currentVoters = self.results.voters, let updatedVoters = results.voters { + var selectedOpaqueIdentifiers = Set() + for voters in currentVoters { + if voters.selected { + selectedOpaqueIdentifiers.insert(voters.opaqueIdentifier) + } + } + updatedResults = TelegramMediaPollResults(voters: updatedVoters.map({ voters in + return TelegramMediaPollOptionVoters(selected: selectedOpaqueIdentifiers.contains(voters.opaqueIdentifier), opaqueIdentifier: voters.opaqueIdentifier, count: voters.count) + }), totalVoters: results.totalVoters) + } else { + updatedResults = TelegramMediaPollResults(voters: self.results.voters, totalVoters: results.totalVoters) + } + } else { + updatedResults = results + } + return TelegramMediaPoll(pollId: self.pollId, text: self.text, options: self.options, results: updatedResults, isClosed: self.isClosed) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaResource.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaResource.swift new file mode 100644 index 0000000000..688e801fc4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaResource.swift @@ -0,0 +1,9 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public protocol TelegramMediaResource: MediaResource, PostboxCoding { +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaWebDocument.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaWebDocument.swift new file mode 100644 index 0000000000..33ac09d3e1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaWebDocument.swift @@ -0,0 +1,83 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public class TelegramMediaWebFile: Media { + public let resource: TelegramMediaResource + public let mimeType: String + public let size: Int32 + public let attributes: [TelegramMediaFileAttribute] + public let peerIds: [PeerId] = [] + + public var id: MediaId? { + return nil + } + + public init(resource: TelegramMediaResource, mimeType: String, size: Int32, attributes: [TelegramMediaFileAttribute]) { + self.resource = resource + self.mimeType = mimeType + self.size = size + self.attributes = attributes + } + + public required init(decoder: PostboxDecoder) { + self.resource = decoder.decodeObjectForKey("r") as! TelegramMediaResource + self.mimeType = decoder.decodeStringForKey("mt", orElse: "") + self.size = decoder.decodeInt32ForKey("s", orElse: 0) + self.attributes = decoder.decodeObjectArrayForKey("at") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObject(self.resource, forKey: "r") + encoder.encodeString(self.mimeType, forKey: "mt") + encoder.encodeInt32(self.size, forKey: "s") + encoder.encodeObjectArray(self.attributes, forKey: "at") + } + + public func isEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaWebFile else { + return false + } + + if !self.resource.isEqual(to: other.resource) { + return false + } + + if self.size != other.size { + return false + } + + if self.mimeType != other.mimeType { + return false + } + + return true + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } + + public var dimensions: CGSize? { + return dimensionsForFileAttributes(self.attributes) + } + + public var duration: Int32? { + return durationForFileAttributes(self.attributes) + } +} + +extension TelegramMediaWebFile { + convenience init(_ document: Api.WebDocument) { + switch document { + case let .webDocument(data): + self.init(resource: WebFileReferenceMediaResource(url: data.url, size: data.size, accessHash: data.accessHash), mimeType: data.mimeType, size: data.size, attributes: telegramMediaFileAttributesFromApiAttributes(data.attributes)) + case let .webDocumentNoProxy(url, size, mimeType, attributes): + self.init(resource: HttpReferenceMediaResource(url: url, size: Int(size)), mimeType: mimeType, size: size, attributes: telegramMediaFileAttributesFromApiAttributes(attributes)) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaWebpage.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaWebpage.swift new file mode 100644 index 0000000000..c1652527b4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaWebpage.swift @@ -0,0 +1,317 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable { + public let url: String + public let displayUrl: String + public let hash: Int32 + public let type: String? + public let websiteName: String? + public let title: String? + public let text: String? + public let embedUrl: String? + public let embedType: String? + public let embedSize: CGSize? + public let duration: Int? + public let author: String? + + public let image: TelegramMediaImage? + public let file: TelegramMediaFile? + public let instantPage: InstantPage? + + public init(url: String, displayUrl: String, hash: Int32, type: String?, websiteName: String?, title: String?, text: String?, embedUrl: String?, embedType: String?, embedSize: CGSize?, duration: Int?, author: String?, image: TelegramMediaImage?, file: TelegramMediaFile?, instantPage: InstantPage?) { + self.url = url + self.displayUrl = displayUrl + self.hash = hash + self.type = type + self.websiteName = websiteName + self.title = title + self.text = text + self.embedUrl = embedUrl + self.embedType = embedType + self.embedSize = embedSize + self.duration = duration + self.author = author + self.image = image + self.file = file + self.instantPage = instantPage + } + + public init(decoder: PostboxDecoder) { + self.url = decoder.decodeStringForKey("u", orElse: "") + self.displayUrl = decoder.decodeStringForKey("d", orElse: "") + self.hash = decoder.decodeInt32ForKey("ha", orElse: 0) + self.type = decoder.decodeOptionalStringForKey("ty") + self.websiteName = decoder.decodeOptionalStringForKey("ws") + self.title = decoder.decodeOptionalStringForKey("ti") + self.text = decoder.decodeOptionalStringForKey("tx") + self.embedUrl = decoder.decodeOptionalStringForKey("eu") + self.embedType = decoder.decodeOptionalStringForKey("et") + if let embedSizeWidth = decoder.decodeOptionalInt32ForKey("esw"), let embedSizeHeight = decoder.decodeOptionalInt32ForKey("esh") { + self.embedSize = CGSize(width: CGFloat(embedSizeWidth), height: CGFloat(embedSizeHeight)) + } else { + self.embedSize = nil + } + if let duration = decoder.decodeOptionalInt32ForKey("du") { + self.duration = Int(duration) + } else { + self.duration = nil + } + self.author = decoder.decodeOptionalStringForKey("au") + + if let image = decoder.decodeObjectForKey("im") as? TelegramMediaImage { + self.image = image + } else { + self.image = nil + } + + if let file = decoder.decodeObjectForKey("fi") as? TelegramMediaFile { + self.file = file + } else { + self.file = nil + } + + if let instantPage = decoder.decodeObjectForKey("ip", decoder: { InstantPage(decoder: $0) }) as? InstantPage { + self.instantPage = instantPage + } else { + self.instantPage = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeString(self.url, forKey: "u") + encoder.encodeString(self.displayUrl, forKey: "d") + encoder.encodeInt32(self.hash, forKey: "ha") + if let type = self.type { + encoder.encodeString(type, forKey: "ty") + } else { + encoder.encodeNil(forKey: "ty") + } + if let websiteName = self.websiteName { + encoder.encodeString(websiteName, forKey: "ws") + } else { + encoder.encodeNil(forKey: "ws") + } + if let title = self.title { + encoder.encodeString(title, forKey: "ti") + } else { + encoder.encodeNil(forKey: "ti") + } + if let text = self.text { + encoder.encodeString(text, forKey: "tx") + } else { + encoder.encodeNil(forKey: "tx") + } + if let embedUrl = self.embedUrl { + encoder.encodeString(embedUrl, forKey: "eu") + } else { + encoder.encodeNil(forKey: "eu") + } + if let embedType = self.embedType { + encoder.encodeString(embedType, forKey: "et") + } else { + encoder.encodeNil(forKey: "et") + } + if let embedSize = self.embedSize { + encoder.encodeInt32(Int32(embedSize.width), forKey: "esw") + encoder.encodeInt32(Int32(embedSize.height), forKey: "esh") + } else { + encoder.encodeNil(forKey: "esw") + encoder.encodeNil(forKey: "esh") + } + if let duration = self.duration { + encoder.encodeInt32(Int32(duration), forKey: "du") + } else { + encoder.encodeNil(forKey: "du") + } + if let author = self.author { + encoder.encodeString(author, forKey: "au") + } else { + encoder.encodeNil(forKey: "au") + } + if let image = self.image { + encoder.encodeObject(image, forKey: "im") + } else { + encoder.encodeNil(forKey: "im") + } + if let file = self.file { + encoder.encodeObject(file, forKey: "fi") + } else { + encoder.encodeNil(forKey: "fi") + } + if let instantPage = self.instantPage { + encoder.encodeObject(instantPage, forKey: "ip") + } else { + encoder.encodeNil(forKey: "ip") + } + } +} + +public func ==(lhs: TelegramMediaWebpageLoadedContent, rhs: TelegramMediaWebpageLoadedContent) -> Bool { + if lhs.url != rhs.url + || lhs.displayUrl != rhs.displayUrl + || lhs.hash != rhs.hash + || lhs.type != rhs.type + || lhs.websiteName != rhs.websiteName + || lhs.title != rhs.title + || lhs.text != rhs.text + || lhs.embedUrl != rhs.embedUrl + || lhs.embedType != rhs.embedType + || lhs.embedSize != rhs.embedSize + || lhs.duration != rhs.duration + || lhs.author != rhs.author { + return false + } + + if let lhsImage = lhs.image, let rhsImage = rhs.image { + if !lhsImage.isEqual(to: rhsImage) { + return false + } + } else if (lhs.image == nil) != (rhs.image == nil) { + return false + } + + if let lhsFile = lhs.file, let rhsFile = rhs.file { + if !lhsFile.isEqual(to: rhsFile) { + return false + } + } else if (lhs.file == nil) != (rhs.file == nil) { + return false + } + + if lhs.instantPage != rhs.instantPage { + return false + } + + return true +} + +public enum TelegramMediaWebpageContent { + case Pending(Int32, String?) + case Loaded(TelegramMediaWebpageLoadedContent) +} + +public final class TelegramMediaWebpage: Media, Equatable { + public var id: MediaId? { + return self.webpageId + } + public let peerIds: [PeerId] = [] + + public let webpageId: MediaId + public let content: TelegramMediaWebpageContent + + public init(webpageId: MediaId, content: TelegramMediaWebpageContent) { + self.webpageId = webpageId + self.content = content + } + + public init(decoder: PostboxDecoder) { + self.webpageId = MediaId(decoder.decodeBytesForKeyNoCopy("i")!) + + if decoder.decodeInt32ForKey("ct", orElse: 0) == 0 { + self.content = .Pending(decoder.decodeInt32ForKey("pendingDate", orElse: 0), decoder.decodeOptionalStringForKey("pendingUrl")) + } else { + self.content = .Loaded(TelegramMediaWebpageLoadedContent(decoder: decoder)) + } + } + + public func encode(_ encoder: PostboxEncoder) { + let buffer = WriteBuffer() + self.webpageId.encodeToBuffer(buffer) + encoder.encodeBytes(buffer, forKey: "i") + + switch self.content { + case let .Pending(date, url): + encoder.encodeInt32(0, forKey: "ct") + encoder.encodeInt32(date, forKey: "pendingDate") + if let url = url { + encoder.encodeString(url, forKey: "pendingUrl") + } else { + encoder.encodeNil(forKey: "pendingUrl") + } + case let .Loaded(loadedContent): + encoder.encodeInt32(1, forKey: "ct") + loadedContent.encode(encoder) + } + } + + public func isLikelyToBeUpdated() -> Bool { + return true + } + + public func isEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaWebpage, self.webpageId == other.webpageId { + return self == other + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } + + public static func ==(lhs: TelegramMediaWebpage, rhs: TelegramMediaWebpage) -> Bool { + if lhs.webpageId != rhs.webpageId { + return false + } + + switch lhs.content { + case let .Pending(lhsDate, lhsUrl): + switch rhs.content { + case let .Pending(rhsDate, rhsUrl): + if lhsDate == rhsDate, lhsUrl == rhsUrl { + return true + } else { + return false + } + default: + return false + } + case let .Loaded(lhsContent): + switch rhs.content { + case let .Loaded(rhsContent) where lhsContent == rhsContent: + return true + default: + return false + } + } + } +} + +func telegramMediaWebpageFromApiWebpage(_ webpage: Api.WebPage, url: String?) -> TelegramMediaWebpage? { + switch webpage { + case .webPageNotModified: + return nil + case let .webPagePending(id, date): + return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Pending(date, url)) + case let .webPage(_, id, url, displayUrl, hash, type, siteName, title, description, photo, embedUrl, embedType, embedWidth, embedHeight, duration, author, document, cachedPage): + var embedSize: CGSize? + if let embedWidth = embedWidth, let embedHeight = embedHeight { + embedSize = CGSize(width: CGFloat(embedWidth), height: CGFloat(embedHeight)) + } + var webpageDuration: Int? + if let duration = duration { + webpageDuration = Int(duration) + } + var image: TelegramMediaImage? + if let photo = photo { + image = telegramMediaImageFromApiPhoto(photo) + } + var file: TelegramMediaFile? + if let document = document { + file = telegramMediaFileFromApiDocument(document) + } + var instantPage: InstantPage? + if let cachedPage = cachedPage { + instantPage = InstantPage(apiPage: cachedPage) + } + return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Loaded(TelegramMediaWebpageLoadedContent(url: url, displayUrl: displayUrl, hash: hash, type: type, websiteName: siteName, title: title, text: description, embedUrl: embedUrl, embedType: embedType, embedSize: embedSize, duration: webpageDuration, author: author, image: image, file: file, instantPage: instantPage))) + case .webPageEmpty: + return nil + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/TelegramCore/TelegramPeerNotificationSettings.swift new file mode 100644 index 0000000000..26785c1b2e --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramPeerNotificationSettings.swift @@ -0,0 +1,296 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum PeerMuteState: Equatable { + case `default` + case unmuted + case muted(until: Int32) + + fileprivate static func decodeInline(_ decoder: PostboxDecoder) -> PeerMuteState { + switch decoder.decodeInt32ForKey("m.v", orElse: 0) { + case 0: + return .default + case 1: + return .muted(until: decoder.decodeInt32ForKey("m.u", orElse: 0)) + case 2: + return .unmuted + default: + return .default + } + } + + fileprivate func encodeInline(_ encoder: PostboxEncoder) { + switch self { + case .default: + encoder.encodeInt32(0, forKey: "m.v") + case let .muted(until): + encoder.encodeInt32(1, forKey: "m.v") + encoder.encodeInt32(until, forKey: "m.u") + case .unmuted: + encoder.encodeInt32(2, forKey: "m.v") + } + } +} + +private enum PeerMessageSoundValue: Int32 { + case none + case bundledModern + case bundledClassic + case `default` +} + +public enum PeerMessageSound: Equatable { + case none + case `default` + case bundledModern(id: Int32) + case bundledClassic(id: Int32) + + static func decodeInline(_ decoder: PostboxDecoder) -> PeerMessageSound { + switch decoder.decodeInt32ForKey("s.v", orElse: 0) { + case PeerMessageSoundValue.none.rawValue: + return .none + case PeerMessageSoundValue.bundledModern.rawValue: + return .bundledModern(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.bundledClassic.rawValue: + return .bundledClassic(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.default.rawValue: + return .default + default: + assertionFailure() + return .bundledModern(id: 0) + } + } + + func encodeInline(_ encoder: PostboxEncoder) { + switch self { + case .none: + encoder.encodeInt32(PeerMessageSoundValue.none.rawValue, forKey: "s.v") + case let .bundledModern(id): + encoder.encodeInt32(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") + encoder.encodeInt32(id, forKey: "s.i") + case let .bundledClassic(id): + encoder.encodeInt32(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") + encoder.encodeInt32(id, forKey: "s.i") + case .default: + encoder.encodeInt32(PeerMessageSoundValue.default.rawValue, forKey: "s.v") + } + } + + public static func ==(lhs: PeerMessageSound, rhs: PeerMessageSound) -> Bool { + switch lhs { + case .none: + if case .none = rhs { + return true + } else { + return false + } + case let .bundledModern(id): + if case .bundledModern(id) = rhs { + return true + } else { + return false + } + case let .bundledClassic(id): + if case .bundledClassic(id) = rhs { + return true + } else { + return false + } + case .default: + if case .default = rhs { + return true + } else { + return false + } + } + } +} + +public enum PeerNotificationDisplayPreviews { + case `default` + case show + case hide + + static func decodeInline(_ decoder: PostboxDecoder) -> PeerNotificationDisplayPreviews { + switch decoder.decodeInt32ForKey("p.v", orElse: 0) { + case 0: + return .default + case 1: + return .show + case 2: + return .hide + default: + assertionFailure() + return .default + } + } + + func encodeInline(_ encoder: PostboxEncoder) { + switch self { + case .default: + encoder.encodeInt32(0, forKey: "p.v") + case .show: + encoder.encodeInt32(0, forKey: "p.v") + case .hide: + encoder.encodeInt32(0, forKey: "p.v") + } + } +} + +public final class TelegramPeerNotificationSettings: PeerNotificationSettings, Equatable { + public let muteState: PeerMuteState + public let messageSound: PeerMessageSound + public let displayPreviews: PeerNotificationDisplayPreviews + + public static var defaultSettings: TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings(muteState: .unmuted, messageSound: .default, displayPreviews: .default) + } + + public var isRemovedFromTotalUnreadCount: Bool { + switch self.muteState { + case .unmuted: + return false + case .muted: + return true + case .default: + return false + } + } + + public var behavior: PeerNotificationSettingsBehavior { + if case let .muted(untilTimestamp) = self.muteState, untilTimestamp < Int32.max { + return .reset(atTimestamp: untilTimestamp, toValue: self.withUpdatedMuteState(.unmuted)) + } else { + return .none + } + } + + public init(muteState: PeerMuteState, messageSound: PeerMessageSound, displayPreviews: PeerNotificationDisplayPreviews) { + self.muteState = muteState + self.messageSound = messageSound + self.displayPreviews = displayPreviews + } + + public init(decoder: PostboxDecoder) { + self.muteState = PeerMuteState.decodeInline(decoder) + self.messageSound = PeerMessageSound.decodeInline(decoder) + self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder) + } + + public func encode(_ encoder: PostboxEncoder) { + self.muteState.encodeInline(encoder) + self.messageSound.encodeInline(encoder) + self.displayPreviews.encodeInline(encoder) + } + + public func isEqual(to: PeerNotificationSettings) -> Bool { + if let to = to as? TelegramPeerNotificationSettings { + return self == to + } else { + return false + } + } + + public func withUpdatedMuteState(_ muteState: PeerMuteState) -> TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings(muteState: muteState, messageSound: self.messageSound, displayPreviews: self.displayPreviews) + } + + public func withUpdatedMessageSound(_ messageSound: PeerMessageSound) -> TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: messageSound, displayPreviews: self.displayPreviews) + } + + public func withUpdatedDisplayPreviews(_ displayPreviews: PeerNotificationDisplayPreviews) -> TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings(muteState: self.muteState, messageSound: self.messageSound, displayPreviews: displayPreviews) + } + + public static func ==(lhs: TelegramPeerNotificationSettings, rhs: TelegramPeerNotificationSettings) -> Bool { + return lhs.muteState == rhs.muteState && lhs.messageSound == rhs.messageSound && lhs.displayPreviews == rhs.displayPreviews + } +} + +extension TelegramPeerNotificationSettings { + convenience init(apiSettings: Api.PeerNotifySettings) { + switch apiSettings { + case .peerNotifySettingsEmpty: + self.init(muteState: .unmuted, messageSound: .bundledModern(id: 0), displayPreviews: .default) + case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): + let muteState: PeerMuteState + if let muteUntil = muteUntil { + if muteUntil == 0 { + muteState = .unmuted + } else { + muteState = .muted(until: muteUntil) + } + } else { + muteState = .default + } + let displayPreviews: PeerNotificationDisplayPreviews + if let showPreviews = showPreviews { + if case .boolTrue = showPreviews { + displayPreviews = .show + } else { + displayPreviews = .hide + } + } else { + displayPreviews = .default + } + self.init(muteState: muteState, messageSound: PeerMessageSound(apiSound: sound), displayPreviews: displayPreviews) + } + } +} + +extension PeerMessageSound { + init(apiSound: String?) { + guard let apiSound = apiSound else { + self = .default + return + } + var rawApiSound = apiSound + if let index = rawApiSound.index(of: ".") { + rawApiSound = String(rawApiSound[..= 100 && soundId <= 111 { + parsedSound = .bundledModern(id: soundId - 100) + } else if soundId >= 2 && soundId <= 9 { + parsedSound = .bundledClassic(id: soundId - 2) + } else { + parsedSound = .bundledModern(id: 0) + } + } + self = parsedSound + } + + var apiSound: String? { + switch self { + case .none: + return "" + case .default: + return nil + case let .bundledModern(id): + if id == 0 { + return "default" + } else { + return "\(id + 100)" + } + case let .bundledClassic(id): + return "\(id + 2)" + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramSecretChat.swift b/submodules/TelegramCore/TelegramCore/TelegramSecretChat.swift new file mode 100644 index 0000000000..7b31ce958c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramSecretChat.swift @@ -0,0 +1,117 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class TelegramSecretChat: Peer { + public let id: PeerId + public let regularPeerId: PeerId + public let accessHash: Int64 + public let creationDate: Int32 + public let role: SecretChatRole + public let embeddedState: SecretChatEmbeddedPeerState + public let messageAutoremoveTimeout: Int32? + + public var indexName: PeerIndexNameRepresentation { + return .title(title: "", addressName: nil) + } + + public let associatedPeerId: PeerId? + public let notificationSettingsPeerId: PeerId? + + public init(id: PeerId, creationDate: Int32, regularPeerId: PeerId, accessHash: Int64, role: SecretChatRole, embeddedState: SecretChatEmbeddedPeerState, messageAutoremoveTimeout: Int32?) { + self.id = id + self.regularPeerId = regularPeerId + self.accessHash = accessHash + self.creationDate = creationDate + self.role = role + self.embeddedState = embeddedState + self.associatedPeerId = regularPeerId + self.notificationSettingsPeerId = regularPeerId + self.messageAutoremoveTimeout = messageAutoremoveTimeout + } + + public init(decoder: PostboxDecoder) { + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + self.regularPeerId = PeerId(decoder.decodeInt64ForKey("r", orElse: 0)) + self.notificationSettingsPeerId = self.regularPeerId + self.accessHash = decoder.decodeInt64ForKey("h", orElse: 0) + self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.role = SecretChatRole(rawValue: decoder.decodeInt32ForKey("o", orElse: 0))! + self.embeddedState = SecretChatEmbeddedPeerState(rawValue: decoder.decodeInt32ForKey("s", orElse: 0))! + self.associatedPeerId = self.regularPeerId + self.messageAutoremoveTimeout = decoder.decodeOptionalInt32ForKey("at") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id.toInt64(), forKey: "i") + encoder.encodeInt64(self.regularPeerId.toInt64(), forKey: "r") + encoder.encodeInt64(self.accessHash, forKey: "h") + encoder.encodeInt32(self.creationDate, forKey: "d") + encoder.encodeInt32(self.role.rawValue, forKey: "o") + encoder.encodeInt32(self.embeddedState.rawValue, forKey: "s") + if let messageAutoremoveTimeout = self.messageAutoremoveTimeout { + encoder.encodeInt32(messageAutoremoveTimeout, forKey: "at") + } else { + encoder.encodeNil(forKey: "at") + } + } + + public func isEqual(_ other: Peer) -> Bool { + if let other = other as? TelegramSecretChat { + return self.id == other.id && self.regularPeerId == other.regularPeerId && self.accessHash == other.accessHash && self.embeddedState == other.embeddedState && self.messageAutoremoveTimeout == other.messageAutoremoveTimeout && self.creationDate == other.creationDate && self.role == other.role + } else { + return false + } + } + + func withUpdatedEmbeddedState(_ embeddedState: SecretChatEmbeddedPeerState) -> TelegramSecretChat { + return TelegramSecretChat(id: self.id, creationDate: self.creationDate, regularPeerId: self.regularPeerId, accessHash: self.accessHash, role: self.role, embeddedState: embeddedState, messageAutoremoveTimeout: self.messageAutoremoveTimeout) + } + + func withUpdatedMessageAutoremoveTimeout(_ messageAutoremoveTimeout: Int32?) -> TelegramSecretChat { + return TelegramSecretChat(id: self.id, creationDate: self.creationDate, regularPeerId: self.regularPeerId, accessHash: self.accessHash, role: self.role, embeddedState: self.embeddedState, messageAutoremoveTimeout: messageAutoremoveTimeout) + } +} + +public final class CachedSecretChatData: CachedPeerData { + public let peerIds: Set = Set() + public let messageIds: Set = Set() + public let associatedHistoryMessageId: MessageId? = nil + + public let peerStatusSettings: PeerStatusSettings? + + public init(peerStatusSettings: PeerStatusSettings?) { + self.peerStatusSettings = peerStatusSettings + } + + public init(decoder: PostboxDecoder) { + if let value = decoder.decodeOptionalInt32ForKey("pcs") { + self.peerStatusSettings = PeerStatusSettings(rawValue: value) + } else { + self.peerStatusSettings = nil + } + } + + public func encode(_ encoder: PostboxEncoder) { + if let peerStatusSettings = self.peerStatusSettings { + encoder.encodeInt32(peerStatusSettings.rawValue, forKey: "pcs") + } else { + encoder.encodeNil(forKey: "pcs") + } + } + + public func isEqual(to: CachedPeerData) -> Bool { + if let to = to as? CachedSecretChatData { + return self.peerStatusSettings == to.peerStatusSettings + } else { + return false + } + } + + func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedSecretChatData { + return CachedSecretChatData(peerStatusSettings: peerStatusSettings) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramUser.swift b/submodules/TelegramCore/TelegramCore/TelegramUser.swift new file mode 100644 index 0000000000..9182029c21 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramUser.swift @@ -0,0 +1,348 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox + import UIKit +#endif + +public struct UserInfoFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let isVerified = UserInfoFlags(rawValue: (1 << 0)) + public static let isSupport = UserInfoFlags(rawValue: (1 << 1)) + public static let isScam = UserInfoFlags(rawValue: (1 << 2)) +} + +public struct BotUserInfoFlags: OptionSet { + public var rawValue: Int32 + + public init() { + self.rawValue = 0 + } + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let hasAccessToChatHistory = BotUserInfoFlags(rawValue: (1 << 0)) + public static let worksWithGroups = BotUserInfoFlags(rawValue: (1 << 1)) + public static let requiresGeolocationForInlineRequests = BotUserInfoFlags(rawValue: (1 << 2)) +} + +public struct BotUserInfo: PostboxCoding, Equatable { + public let flags: BotUserInfoFlags + public let inlinePlaceholder: String? + + init(flags: BotUserInfoFlags, inlinePlaceholder: String?) { + self.flags = flags + self.inlinePlaceholder = inlinePlaceholder + } + + public init(decoder: PostboxDecoder) { + self.flags = BotUserInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) + self.inlinePlaceholder = decoder.decodeOptionalStringForKey("ip") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.flags.rawValue, forKey: "f") + if let inlinePlaceholder = self.inlinePlaceholder { + encoder.encodeString(inlinePlaceholder, forKey: "ip") + } else { + encoder.encodeNil(forKey: "ip") + } + } + + public static func ==(lhs: BotUserInfo, rhs: BotUserInfo) -> Bool { + return lhs.flags == rhs.flags && lhs.inlinePlaceholder == rhs.inlinePlaceholder + } +} + +public final class TelegramUser: Peer { + public let id: PeerId + public let accessHash: Int64? + public let firstName: String? + public let lastName: String? + public let username: String? + public let phone: String? + public let photo: [TelegramMediaImageRepresentation] + public let botInfo: BotUserInfo? + public let restrictionInfo: PeerAccessRestrictionInfo? + public let flags: UserInfoFlags + + public var name: String { + if let firstName = self.firstName { + if let lastName = self.lastName { + return "\(firstName) \(lastName)" + } else { + return firstName + } + } else if let lastName = self.lastName { + return lastName + } else { + return "" + } + } + + public var indexName: PeerIndexNameRepresentation { + return .personName(first: self.firstName ?? "", last: self.lastName ?? "", addressName: self.username, phoneNumber: self.phone) + } + + public let associatedPeerId: PeerId? = nil + public let notificationSettingsPeerId: PeerId? = nil + + public init(id: PeerId, accessHash: Int64?, firstName: String?, lastName: String?, username: String?, phone: String?, photo: [TelegramMediaImageRepresentation], botInfo: BotUserInfo?, restrictionInfo: PeerAccessRestrictionInfo?, flags: UserInfoFlags) { + self.id = id + self.accessHash = accessHash + self.firstName = firstName + self.lastName = lastName + self.username = username + self.phone = phone + self.photo = photo + self.botInfo = botInfo + self.restrictionInfo = restrictionInfo + self.flags = flags + } + + public init(decoder: PostboxDecoder) { + self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) + + let accessHash: Int64 = decoder.decodeInt64ForKey("ah", orElse: 0) + if accessHash != 0 { + self.accessHash = accessHash + } else { + self.accessHash = nil + } + + self.firstName = decoder.decodeOptionalStringForKey("fn") + self.lastName = decoder.decodeOptionalStringForKey("ln") + + self.username = decoder.decodeOptionalStringForKey("un") + self.phone = decoder.decodeOptionalStringForKey("p") + + self.photo = decoder.decodeObjectArrayForKey("ph") + + if let botInfo = decoder.decodeObjectForKey("bi", decoder: { return BotUserInfo(decoder: $0) }) as? BotUserInfo { + self.botInfo = botInfo + } else { + self.botInfo = nil + } + + self.restrictionInfo = decoder.decodeObjectForKey("ri") as? PeerAccessRestrictionInfo + + self.flags = UserInfoFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt64(self.id.toInt64(), forKey: "i") + + if let accessHash = self.accessHash { + encoder.encodeInt64(accessHash, forKey: "ah") + } + + if let firstName = self.firstName { + encoder.encodeString(firstName, forKey: "fn") + } + if let lastName = self.lastName { + encoder.encodeString(lastName, forKey: "ln") + } + + if let username = self.username { + encoder.encodeString(username, forKey: "un") + } + if let phone = self.phone { + encoder.encodeString(phone, forKey: "p") + } + + encoder.encodeObjectArray(self.photo, forKey: "ph") + + if let botInfo = self.botInfo { + encoder.encodeObject(botInfo, forKey: "bi") + } else { + encoder.encodeNil(forKey: "bi") + } + + if let restrictionInfo = self.restrictionInfo { + encoder.encodeObject(restrictionInfo, forKey: "ri") + } else { + encoder.encodeNil(forKey: "ri") + } + + encoder.encodeInt32(self.flags.rawValue, forKey: "fl") + } + + public func isEqual(_ other: Peer) -> Bool { + if let other = other as? TelegramUser { + if self.id != other.id { + return false + } + if self.accessHash != other.accessHash { + return false + } + if self.firstName != other.firstName { + return false + } + if self.lastName != other.lastName { + return false + } + if self.phone != other.phone { + return false + } + if self.photo.count != other.photo.count { + return false + } + for i in 0 ..< self.photo.count { + if self.photo[i] != other.photo[i] { + return false + } + } + if self.botInfo != other.botInfo { + return false + } + if self.restrictionInfo != other.restrictionInfo { + return false + } + + if self.flags != other.flags { + return false + } + + return true + } else { + return false + } + } + + func withUpdatedUsername(_ username:String?) -> TelegramUser { + return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: username, phone: self.phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags) + } + + func withUpdatedNames(firstName: String?, lastName: String?) -> TelegramUser { + return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: firstName, lastName: lastName, username: self.username, phone: self.phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags) + } + + func withUpdatedPhone(_ phone: String?) -> TelegramUser { + return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: self.username, phone: phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags) + } + + func withUpdatedPhoto(_ representations: [TelegramMediaImageRepresentation]) -> TelegramUser { + return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: self.username, phone: phone, photo: representations, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags) + } +} + +func parsedTelegramProfilePhoto(_ photo: Api.UserProfilePhoto) -> [TelegramMediaImageRepresentation] { + var representations: [TelegramMediaImageRepresentation] = [] + switch photo { + case let .userProfilePhoto(photoId, photoSmall, photoBig, dcId): + let smallResource: TelegramMediaResource + let fullSizeResource: TelegramMediaResource + switch photoSmall { + case let .fileLocationToBeDeprecated(volumeId, localId): + smallResource = CloudPeerPhotoSizeMediaResource(datacenterId: dcId, sizeSpec: .small, volumeId: volumeId, localId: localId) + } + switch photoBig { + case let .fileLocationToBeDeprecated(volumeId, localId): + fullSizeResource = CloudPeerPhotoSizeMediaResource(datacenterId: dcId, sizeSpec: .fullSize, volumeId: volumeId, localId: localId) + } + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: 80.0, height: 80.0), resource: smallResource)) + representations.append(TelegramMediaImageRepresentation(dimensions: CGSize(width: 640.0, height: 640.0), resource: fullSizeResource)) + case .userProfilePhotoEmpty: + break + } + return representations +} + +extension TelegramUser { + convenience init(user: Api.User) { + switch user { + case let .user(flags, id, accessHash, firstName, lastName, username, phone, photo, _, _, restrictionReason, botInlinePlaceholder, _): + let representations: [TelegramMediaImageRepresentation] = photo.flatMap(parsedTelegramProfilePhoto) ?? [] + + var userFlags: UserInfoFlags = [] + if (flags & (1 << 17)) != 0 { + userFlags.insert(.isVerified) + } + if (flags & (1 << 23)) != 0 { + userFlags.insert(.isSupport) + } + if (flags & (1 << 24)) != 0 { + userFlags.insert(.isScam) + } + + var botInfo: BotUserInfo? + if (flags & (1 << 14)) != 0 { + var botFlags = BotUserInfoFlags() + if (flags & (1 << 15)) != 0 { + botFlags.insert(.hasAccessToChatHistory) + } + if (flags & (1 << 16)) == 0 { + botFlags.insert(.worksWithGroups) + } + if (flags & (1 << 21)) == 0 { + botFlags.insert(.requiresGeolocationForInlineRequests) + } + botInfo = BotUserInfo(flags: botFlags, inlinePlaceholder: botInlinePlaceholder) + } + + let restrictionInfo: PeerAccessRestrictionInfo? = restrictionReason.flatMap(PeerAccessRestrictionInfo.init) + + self.init(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: id), accessHash: accessHash, firstName: firstName, lastName: lastName, username: username, phone: phone, photo: representations, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags) + case let .userEmpty(id): + self.init(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: id), accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) + } + } + + static func merge(_ lhs: TelegramUser?, rhs: Api.User) -> TelegramUser? { + switch rhs { + case let .user(flags, _, accessHash, _, _, username, _, photo, _, _, restrictionReason, botInlinePlaceholder, _): + if let _ = accessHash { + return TelegramUser(user: rhs) + } else { + let telegramPhoto = photo.flatMap(parsedTelegramProfilePhoto) ?? [] + if let lhs = lhs { + var userFlags: UserInfoFlags = [] + if (flags & (1 << 17)) != 0 { + userFlags.insert(.isVerified) + } + if (flags & (1 << 23)) != 0 { + userFlags.insert(.isSupport) + } + if (flags & (1 << 24)) != 0 { + userFlags.insert(.isScam) + } + + var botInfo: BotUserInfo? + if (flags & (1 << 14)) != 0 { + var botFlags = BotUserInfoFlags() + if (flags & (1 << 15)) != 0 { + botFlags.insert(.hasAccessToChatHistory) + } + if (flags & (1 << 16)) == 0 { + botFlags.insert(.worksWithGroups) + } + if (flags & (1 << 21)) == 0 { + botFlags.insert(.requiresGeolocationForInlineRequests) + } + botInfo = BotUserInfo(flags: botFlags, inlinePlaceholder: botInlinePlaceholder) + } + + let restrictionInfo: PeerAccessRestrictionInfo? = restrictionReason.flatMap(PeerAccessRestrictionInfo.init) + + return TelegramUser(id: lhs.id, accessHash: lhs.accessHash, firstName: lhs.firstName, lastName: lhs.lastName, username: username, phone: lhs.phone, photo: telegramPhoto, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags) + } else { + return TelegramUser(user: rhs) + } + } + case .userEmpty: + return TelegramUser(user: rhs) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TelegramUserPresence.swift b/submodules/TelegramCore/TelegramCore/TelegramUserPresence.swift new file mode 100644 index 0000000000..cc7e494924 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TelegramUserPresence.swift @@ -0,0 +1,153 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum UserPresenceStatus: Comparable, PostboxCoding { + case none + case present(until: Int32) + case recently + case lastWeek + case lastMonth + + public static func <(lhs: UserPresenceStatus, rhs: UserPresenceStatus) -> Bool { + switch lhs { + case .none: + switch rhs { + case .none: + return false + case .lastMonth, .lastWeek, .recently, .present: + return true + } + case let .present(until): + switch rhs { + case .none: + return false + case let .present(rhsUntil): + return until < rhsUntil + case .lastWeek, .lastMonth, .recently: + return false + } + case .recently: + switch rhs { + case .none, .lastWeek, .lastMonth, .recently: + return false + case .present: + return true + } + case .lastWeek: + switch rhs { + case .none, .lastMonth, .lastWeek: + return false + case .present, .recently: + return true + } + case .lastMonth: + switch rhs { + case .none, .lastMonth: + return false + case .present, .recently, lastWeek: + return true + } + } + } + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case 0: + self = .none + case 1: + self = .present(until: decoder.decodeInt32ForKey("t", orElse: 0)) + case 2: + self = .recently + case 3: + self = .lastWeek + case 4: + self = .lastMonth + default: + self = .none + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case .none: + encoder.encodeInt32(0, forKey: "v") + case let .present(timestamp): + encoder.encodeInt32(1, forKey: "v") + encoder.encodeInt32(timestamp, forKey: "t") + case .recently: + encoder.encodeInt32(2, forKey: "v") + case .lastWeek: + encoder.encodeInt32(3, forKey: "v") + case .lastMonth: + encoder.encodeInt32(4, forKey: "v") + } + } +} + +public final class TelegramUserPresence: PeerPresence, Equatable { + public let status: UserPresenceStatus + public let lastActivity: Int32 + + public init(status: UserPresenceStatus, lastActivity: Int32) { + self.status = status + self.lastActivity = lastActivity + } + + public init(decoder: PostboxDecoder) { + self.status = UserPresenceStatus(decoder: decoder) + self.lastActivity = decoder.decodeInt32ForKey("la", orElse: 0) + } + + public func encode(_ encoder: PostboxEncoder) { + self.status.encode(encoder) + encoder.encodeInt32(self.lastActivity, forKey: "la") + } + + public static func ==(lhs: TelegramUserPresence, rhs: TelegramUserPresence) -> Bool { + return lhs.status == rhs.status && lhs.lastActivity == rhs.lastActivity + } + + public func isEqual(to: PeerPresence) -> Bool { + if let to = to as? TelegramUserPresence { + return self == to + } else { + return false + } + } +} + +extension TelegramUserPresence { + convenience init(apiStatus: Api.UserStatus) { + switch apiStatus { + case .userStatusEmpty: + self.init(status: .none, lastActivity: 0) + case let .userStatusOnline(expires): + self.init(status: .present(until: expires), lastActivity: 0) + case let .userStatusOffline(wasOnline): + self.init(status: .present(until: wasOnline), lastActivity: 0) + case .userStatusRecently: + self.init(status: .recently, lastActivity: 0) + case .userStatusLastWeek: + self.init(status: .lastWeek, lastActivity: 0) + case .userStatusLastMonth: + self.init(status: .lastMonth, lastActivity: 0) + } + } + + convenience init?(apiUser: Api.User) { + switch apiUser { + case let .user(_, _, _, _, _, _, _, _, status, _, _, _, _): + if let status = status { + self.init(apiStatus: status) + } else { + self.init(status: .none, lastActivity: 0) + } + case .userEmpty: + return nil + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/TeleramMediaUnsupported.swift b/submodules/TelegramCore/TelegramCore/TeleramMediaUnsupported.swift new file mode 100644 index 0000000000..5ff9e8b0f0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TeleramMediaUnsupported.swift @@ -0,0 +1,31 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public final class TelegramMediaUnsupported: Media { + public let id: MediaId? = nil + public let peerIds: [PeerId] = [] + + init() { + } + + public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } + + public func isEqual(to other: Media) -> Bool { + if other is TelegramMediaUnsupported { + return true + } + return false + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } +} diff --git a/submodules/TelegramCore/TelegramCore/TermsOfService.swift b/submodules/TelegramCore/TelegramCore/TermsOfService.swift new file mode 100644 index 0000000000..bc49519de4 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TermsOfService.swift @@ -0,0 +1,80 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import MtProtoKitMac +#else +import Postbox +import SwiftSignalKit +#if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct TermsOfServiceUpdate: Equatable { + public let id: String + public let text: String + public let entities: [MessageTextEntity] + public let ageConfirmation: Int32? + + init(id: String, text: String, entities: [MessageTextEntity], ageConfirmation: Int32?) { + self.id = id + self.text = text + self.entities = entities + self.ageConfirmation = ageConfirmation + } +} + +extension TermsOfServiceUpdate { + init?(apiTermsOfService: Api.help.TermsOfService) { + switch apiTermsOfService { + case let .termsOfService(_, id, text, entities, minAgeConfirm): + let idData: String + switch id { + case let .dataJSON(data): + idData = data + } + self.init(id: idData, text: text, entities: messageTextEntitiesFromApiEntities(entities), ageConfirmation: minAgeConfirm) + } + } +} + +public func acceptTermsOfService(account: Account, id: String) -> Signal { + return account.network.request(Api.functions.help.acceptTermsOfService(id: .dataJSON(data: id))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { [weak account] _ -> Signal in + account?.stateManager.modifyTermsOfServiceUpdate({ _ in nil }) + return .complete() + } +} + +public func resetAccountDueTermsOfService(network: Network) -> Signal { + return network.request(Api.functions.account.deleteAccount(reason: "Decline ToS update")) + |> retryRequest + |> map { _ in return } +} + +func managedTermsOfServiceUpdates(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { + let poll = network.request(Api.functions.help.getTermsOfServiceUpdate()) + |> retryRequest + |> mapToSignal { [weak stateManager] result -> Signal in + var updated: TermsOfServiceUpdate? + switch result { + case let .termsOfServiceUpdate(_, termsOfService): + updated = TermsOfServiceUpdate(apiTermsOfService: termsOfService) + case let .termsOfServiceUpdateEmpty(expires): + break + } + stateManager?.modifyTermsOfServiceUpdate { _ in + return updated + } + return .complete() + } + + return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} + diff --git a/submodules/TelegramCore/TelegramCore/TextEntitiesMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/TextEntitiesMessageAttribute.swift new file mode 100644 index 0000000000..16f27b8917 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TextEntitiesMessageAttribute.swift @@ -0,0 +1,323 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public enum MessageTextEntityType: Equatable { + public typealias CustomEntityType = Int32 + + case Unknown + case Mention + case Hashtag + case BotCommand + case Url + case Email + case Bold + case Italic + case Code + case Pre + case TextUrl(url: String) + case TextMention(peerId: PeerId) + case PhoneNumber + case Strikethrough + case BlockQuote + case Underline + case Custom(type: CustomEntityType) + + public static func ==(lhs: MessageTextEntityType, rhs: MessageTextEntityType) -> Bool { + switch lhs { + case .Unknown: + if case .Unknown = rhs { + return true + } else { + return false + } + case .Mention: + if case .Mention = rhs { + return true + } else { + return false + } + case .Hashtag: + if case .Hashtag = rhs { + return true + } else { + return false + } + case .BotCommand: + if case .BotCommand = rhs { + return true + } else { + return false + } + case .Url: + if case .Url = rhs { + return true + } else { + return false + } + case .Email: + if case .Email = rhs { + return true + } else { + return false + } + case .Bold: + if case .Bold = rhs { + return true + } else { + return false + } + case .Italic: + if case .Italic = rhs { + return true + } else { + return false + } + case .Code: + if case .Code = rhs { + return true + } else { + return false + } + case .Pre: + if case .Pre = rhs { + return true + } else { + return false + } + case let .TextUrl(url): + if case .TextUrl(url) = rhs { + return true + } else { + return false + } + case let .TextMention(peerId): + if case .TextMention(peerId) = rhs { + return true + } else { + return false + } + case .PhoneNumber: + if case .PhoneNumber = rhs { + return true + } else { + return false + } + case .Strikethrough: + if case .Strikethrough = rhs { + return true + } else { + return false + } + case .BlockQuote: + if case .BlockQuote = rhs { + return true + } else { + return false + } + case .Underline: + if case .Underline = rhs { + return true + } else { + return false + } + case let .Custom(type): + if case .Custom(type) = rhs { + return true + } else { + return false + } + } + } +} + +public struct MessageTextEntity: PostboxCoding, Equatable { + public let range: Range + public let type: MessageTextEntityType + + public init(range: Range, type: MessageTextEntityType) { + self.range = range + self.type = type + } + + public init(decoder: PostboxDecoder) { + self.range = Int(decoder.decodeInt32ForKey("start", orElse: 0)) ..< Int(decoder.decodeInt32ForKey("end", orElse: 0)) + let type: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) + switch type { + case 1: + self.type = .Mention + case 2: + self.type = .Hashtag + case 3: + self.type = .BotCommand + case 4: + self.type = .Url + case 5: + self.type = .Email + case 6: + self.type = .Bold + case 7: + self.type = .Italic + case 8: + self.type = .Code + case 9: + self.type = .Pre + case 10: + self.type = .TextUrl(url: decoder.decodeStringForKey("url", orElse: "")) + case 11: + self.type = .TextMention(peerId: PeerId(decoder.decodeInt64ForKey("peerId", orElse: 0))) + case 12: + self.type = .PhoneNumber + case 13: + self.type = .Strikethrough + case 14: + self.type = .BlockQuote + case 15: + self.type = .Underline + case Int32.max: + self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0)) + default: + self.type = .Unknown + } + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.range.lowerBound), forKey: "start") + encoder.encodeInt32(Int32(self.range.upperBound), forKey: "end") + switch self.type { + case .Unknown: + encoder.encodeInt32(0, forKey: "_rawValue") + case .Mention: + encoder.encodeInt32(1, forKey: "_rawValue") + case .Hashtag: + encoder.encodeInt32(2, forKey: "_rawValue") + case .BotCommand: + encoder.encodeInt32(3, forKey: "_rawValue") + case .Url: + encoder.encodeInt32(4, forKey: "_rawValue") + case .Email: + encoder.encodeInt32(5, forKey: "_rawValue") + case .Bold: + encoder.encodeInt32(6, forKey: "_rawValue") + case .Italic: + encoder.encodeInt32(7, forKey: "_rawValue") + case .Code: + encoder.encodeInt32(8, forKey: "_rawValue") + case .Pre: + encoder.encodeInt32(9, forKey: "_rawValue") + case let .TextUrl(url): + encoder.encodeInt32(10, forKey: "_rawValue") + encoder.encodeString(url, forKey: "url") + case let .TextMention(peerId): + encoder.encodeInt32(11, forKey: "_rawValue") + encoder.encodeInt64(peerId.toInt64(), forKey: "peerId") + case .PhoneNumber: + encoder.encodeInt32(12, forKey: "_rawValue") + case .Strikethrough: + encoder.encodeInt32(13, forKey: "_rawValue") + case .BlockQuote: + encoder.encodeInt32(14, forKey: "_rawValue") + case .Underline: + encoder.encodeInt32(15, forKey: "_rawValue") + case let .Custom(type): + encoder.encodeInt32(Int32.max, forKey: "_rawValue") + encoder.encodeInt32(type, forKey: "type") + } + } + + public static func ==(lhs: MessageTextEntity, rhs: MessageTextEntity) -> Bool { + return lhs.range == rhs.range && lhs.type == rhs.type + } +} + +public class TextEntitiesMessageAttribute: MessageAttribute, Equatable { + public let entities: [MessageTextEntity] + + public var associatedPeerIds: [PeerId] { + var result: [PeerId] = [] + for entity in entities { + switch entity.type { + case let .TextMention(peerId): + result.append(peerId) + default: + break + } + } + return result + } + + public init(entities: [MessageTextEntity]) { + self.entities = entities + } + + required public init(decoder: PostboxDecoder) { + self.entities = decoder.decodeObjectArrayWithDecoderForKey("entities") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.entities, forKey: "entities") + } + + public static func ==(lhs: TextEntitiesMessageAttribute, rhs: TextEntitiesMessageAttribute) -> Bool { + return lhs.entities == rhs.entities + } +} + +func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associatedPeers: SimpleDictionary) -> [Api.MessageEntity] { + var apiEntities: [Api.MessageEntity] = [] + + for entity in entities { + let offset: Int32 = Int32(entity.range.lowerBound) + let length: Int32 = Int32(entity.range.upperBound - entity.range.lowerBound) + switch entity.type { + case .Unknown: + break + case .Mention: + apiEntities.append(.messageEntityMention(offset: offset, length: length)) + case .Hashtag: + apiEntities.append(.messageEntityHashtag(offset: offset, length: length)) + case .BotCommand: + apiEntities.append(.messageEntityBotCommand(offset: offset, length: length)) + case .Url: + apiEntities.append(.messageEntityUrl(offset: offset, length: length)) + case .Email: + apiEntities.append(.messageEntityEmail(offset: offset, length: length)) + case .Bold: + apiEntities.append(.messageEntityBold(offset: offset, length: length)) + case .Italic: + apiEntities.append(.messageEntityItalic(offset: offset, length: length)) + case .Code: + apiEntities.append(.messageEntityCode(offset: offset, length: length)) + case .Pre: + apiEntities.append(.messageEntityPre(offset: offset, length: length, language: "")) + case let .TextUrl(url): + apiEntities.append(.messageEntityTextUrl(offset: offset, length: length, url: url)) + case let .TextMention(peerId): + if let peer = associatedPeers[peerId], let inputUser = apiInputUser(peer) { + apiEntities.append(.inputMessageEntityMentionName(offset: offset, length: length, userId: inputUser)) + } + case .PhoneNumber: + break + case .Strikethrough: + apiEntities.append(.messageEntityStrike(offset: offset, length: length)) + break + case .BlockQuote: + apiEntities.append(.messageEntityBlockquote(offset: offset, length: length)) + break + case .Underline: + apiEntities.append(.messageEntityUnderline(offset: offset, length: length)) + break + case .Custom: + break + } + } + + return apiEntities +} + +func apiTextAttributeEntities(_ attribute: TextEntitiesMessageAttribute, associatedPeers: SimpleDictionary) -> [Api.MessageEntity] { + return apiEntitiesFromMessageTextEntities(attribute.entities, associatedPeers: associatedPeers) +} diff --git a/submodules/TelegramCore/TelegramCore/ToggleChannelSignatures.swift b/submodules/TelegramCore/TelegramCore/ToggleChannelSignatures.swift new file mode 100644 index 0000000000..8b5e1dc2d9 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ToggleChannelSignatures.swift @@ -0,0 +1,26 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) as? TelegramChannel, let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.toggleSignatures(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> retryRequest |> map { updates -> Void in + account.stateManager.addUpdates(updates) + } + } else { + return .complete() + } + } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/TogglePeerChatPinned.swift b/submodules/TelegramCore/TelegramCore/TogglePeerChatPinned.swift new file mode 100644 index 0000000000..895026bc3d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TogglePeerChatPinned.swift @@ -0,0 +1,68 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public enum TogglePeerChatPinnedResult { + case done + case limitExceeded(Int) +} + +public func toggleItemPinned(postbox: Postbox, groupId: PeerGroupId, itemId: PinnedItemId) -> Signal { + return postbox.transaction { transaction -> TogglePeerChatPinnedResult in + var itemIds = transaction.getPinnedItemIds(groupId: groupId) + let sameKind = itemIds.filter { item in + switch itemId { + case let .peer(lhsPeerId): + if case let .peer(rhsPeerId) = item { + return (lhsPeerId.namespace == Namespaces.Peer.SecretChat) == (rhsPeerId.namespace == Namespaces.Peer.SecretChat) && lhsPeerId != rhsPeerId + } else { + return false + } + } + + } + + let additionalCount: Int + if let _ = itemIds.index(of: itemId) { + additionalCount = -1 + } else { + additionalCount = 1 + } + + let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + let limitCount: Int + if case .root = groupId { + limitCount = Int(limitsConfiguration.maxPinnedChatCount) + } else { + limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount) + } + + if sameKind.count + additionalCount > limitCount { + return .limitExceeded(limitCount) + } else { + if let index = itemIds.index(of: itemId) { + itemIds.remove(at: index) + } else { + itemIds.insert(itemId, at: 0) + } + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds) + return .done + } + } +} + +public func reorderPinnedItemIds(transaction: Transaction, groupId: PeerGroupId, itemIds: [PinnedItemId]) -> Bool { + if transaction.getPinnedItemIds(groupId: groupId) != itemIds { + transaction.setPinnedItemIds(groupId: groupId, itemIds: itemIds) + addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) + return true + } else { + return false + } +} diff --git a/submodules/TelegramCore/TelegramCore/TwoStepVerification.swift b/submodules/TelegramCore/TelegramCore/TwoStepVerification.swift new file mode 100644 index 0000000000..4c253cd81c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/TwoStepVerification.swift @@ -0,0 +1,439 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum TwoStepVerificationConfiguration { + case notSet(pendingEmail: TwoStepVerificationPendingEmail?) + case set(hint: String, hasRecoveryEmail: Bool, pendingEmail: TwoStepVerificationPendingEmail?, hasSecureValues: Bool) +} + +public func twoStepVerificationConfiguration(account: Account) -> Signal { + return account.network.request(Api.functions.account.getPassword()) + |> retryRequest + |> map { result -> TwoStepVerificationConfiguration in + switch result { + case let .password(password): + if password.currentAlgo != nil { + return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (password.flags & (1 << 1)) != 0) + } else { + return .notSet(pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) })) + } + } + } +} + +public struct TwoStepVerificationSecureSecret { + public let data: Data + public let derivation: TwoStepSecurePasswordDerivation + public let id: Int64 +} + +public struct TwoStepVerificationSettings { + public let email: String + public let secureSecret: TwoStepVerificationSecureSecret? +} + +public func requestTwoStepVerifiationSettings(network: Network, password: String) -> Signal { + return twoStepAuthData(network) + |> mapError { error -> AuthorizationPasswordVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .invalidPassword + } else { + return .generic + } + } + |> mapToSignal { authData -> Signal in + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { + return .fail(.generic) + } + + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + + return network.request(Api.functions.account.getPasswordSettings(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false) + |> mapError { error -> AuthorizationPasswordVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .invalidPassword + } else { + return .generic + } + } + |> mapToSignal { result -> Signal in + switch result { + case let .passwordSettings(_, email, secureSettings): + var parsedSecureSecret: TwoStepVerificationSecureSecret? + if let secureSettings = secureSettings { + switch secureSettings { + case let .secureSecretSettings(secureAlgo, secureSecret, secureSecretId): + if secureSecret.size != 32 { + return .fail(.generic) + } + parsedSecureSecret = TwoStepVerificationSecureSecret(data: secureSecret.makeData(), derivation: TwoStepSecurePasswordDerivation(secureAlgo), id: secureSecretId) + } + } + return .single(TwoStepVerificationSettings(email: email ?? "", secureSecret: parsedSecureSecret)) + } + } + } +} + +public enum UpdateTwoStepVerificationPasswordError { + case generic + case invalidEmail +} + +public struct TwoStepVerificationPendingEmail { + public let pattern: String + public let codeLength: Int32? + + public init(pattern: String, codeLength: Int32?) { + self.pattern = pattern + self.codeLength = codeLength + } +} + +public enum UpdateTwoStepVerificationPasswordResult { + case none + case password(password: String, pendingEmail: TwoStepVerificationPendingEmail?) +} + +public enum UpdatedTwoStepVerificationPassword { + case none + case password(password: String, hint: String, email: String?) +} + +public func updateTwoStepVerificationPassword(network: Network, currentPassword: String?, updatedPassword: UpdatedTwoStepVerificationPassword) -> Signal { + return twoStepAuthData(network) + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in + return .generic + } + |> mapToSignal { authData -> Signal in + if let _ = authData.currentPasswordDerivation { + return requestTwoStepVerifiationSettings(network: network, password: currentPassword ?? "") + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in + return .generic + } + |> map { settings in + return settings.secureSecret + } + } else { + return .single(nil) + } + } + |> mapToSignal { secureSecret -> Signal<(TwoStepAuthData, TwoStepVerificationSecureSecret?), UpdateTwoStepVerificationPasswordError> in + return twoStepAuthData(network) + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in + return .generic + } + |> map { authData -> (TwoStepAuthData, TwoStepVerificationSecureSecret?) in + return (authData, secureSecret) + } + } + |> mapToSignal { authData, secureSecret -> Signal in + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + if let kdfResult = passwordKDF(password: currentPassword ?? "", derivation: currentPasswordDerivation, srpSessionData: srpSessionData) { + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + } else { + return .fail(.generic) + } + } else { + checkPassword = .inputCheckPasswordEmpty + } + + switch updatedPassword { + case .none: + var flags: Int32 = (1 << 1) + if authData.currentPasswordDerivation != nil { + flags |= (1 << 0) + } + + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: .passwordInputSettings(flags: flags, newAlgo: .passwordKdfAlgoUnknown, newPasswordHash: Buffer(data: Data()), hint: "", email: "", newSecureSettings: nil)), automaticFloodWait: true) + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in + return .generic + } + |> map { _ -> UpdateTwoStepVerificationPasswordResult in + return .none + } + case let .password(password, hint, email): + var flags: Int32 = 1 << 0 + if email != nil { + flags |= (1 << 1) + } + + guard let (updatedPasswordHash, updatedPasswordDerivation) = passwordUpdateKDF(password: password, derivation: authData.nextPasswordDerivation) else { + return .fail(.generic) + } + + var updatedSecureSecret: TwoStepVerificationSecureSecret? + if let encryptedSecret = secureSecret { + if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: encryptedSecret.data, password: currentPassword ?? "", derivation: encryptedSecret.derivation, id: encryptedSecret.id) { + if let (data, derivation, id) = encryptedSecureSecret(secretData: decryptedSecret, password: password, inputDerivation: authData.nextSecurePasswordDerivation) { + updatedSecureSecret = TwoStepVerificationSecureSecret(data: data, derivation: derivation, id: id) + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + + var updatedSecureSettings: Api.SecureSecretSettings? + if let updatedSecureSecret = updatedSecureSecret { + flags |= 1 << 2 + updatedSecureSettings = .secureSecretSettings(secureAlgo: updatedSecureSecret.derivation.apiAlgo, secureSecret: Buffer(data: updatedSecureSecret.data), secureSecretId: updatedSecureSecret.id) + } + + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: updatedPasswordDerivation.apiAlgo, newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSettings: updatedSecureSettings)), automaticFloodWait: false) + |> map { _ -> UpdateTwoStepVerificationPasswordResult in + return .password(password: password, pendingEmail: nil) + } + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("EMAIL_UNCONFIRMED") { + var codeLength: Int32? + if error.errorDescription.hasPrefix("EMAIL_UNCONFIRMED_") { + if let value = Int32(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "EMAIL_UNCONFIRMED_".count)...]) { + codeLength = value + } + } + return twoStepAuthData(network) + |> map { result -> UpdateTwoStepVerificationPasswordResult in + return .password(password: password, pendingEmail: result.unconfirmedEmailPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: codeLength) })) + } + } else { + return .fail(error) + } + } + |> mapError { error -> UpdateTwoStepVerificationPasswordError in + if error.errorDescription == "EMAIL_INVALID" { + return .invalidEmail + } else { + return .generic + } + } + } + } +} + +enum UpdateTwoStepVerificationSecureSecretResult { + case success +} + +enum UpdateTwoStepVerificationSecureSecretError { + case generic +} + +func updateTwoStepVerificationSecureSecret(network: Network, password: String, secret: Data) -> Signal { + return twoStepAuthData(network) + |> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in + return .generic + } + |> mapToSignal { authData -> Signal in + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { + return .fail(.generic) + } + + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + + let checkPassword: Api.InputCheckPasswordSRP = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + + guard let (encryptedSecret, secretDerivation, secretId) = encryptedSecureSecret(secretData: secret, password: password, inputDerivation: authData.nextSecurePasswordDerivation) else { + return .fail(.generic) + } + + let flags: Int32 = (1 << 2) + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: "", email: "", newSecureSettings: .secureSecretSettings(secureAlgo: secretDerivation.apiAlgo, secureSecret: Buffer(data: encryptedSecret), secureSecretId: secretId))), automaticFloodWait: true) + |> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in + return .generic + } + |> map { _ -> UpdateTwoStepVerificationSecureSecretResult in + return .success + } + } +} + +public func updateTwoStepVerificationEmail(network: Network, currentPassword: String, updatedEmail: String) -> Signal { + return twoStepAuthData(network) + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in + return .generic + } + |> mapToSignal { authData -> Signal in + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + guard let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(.generic) + } + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + } else { + checkPassword = .inputCheckPasswordEmpty + } + + let flags: Int32 = 1 << 1 + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: updatedEmail, newSecureSettings: nil)), automaticFloodWait: false) + |> map { _ -> UpdateTwoStepVerificationPasswordResult in + return .password(password: currentPassword, pendingEmail: nil) + } + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("EMAIL_UNCONFIRMED") { + return twoStepAuthData(network) + |> map { result -> UpdateTwoStepVerificationPasswordResult in + var codeLength: Int32? + if error.errorDescription.hasPrefix("EMAIL_UNCONFIRMED_") { + if let value = Int32(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "EMAIL_UNCONFIRMED_".count)...]) { + codeLength = value + } + } + return .password(password: currentPassword, pendingEmail: result.unconfirmedEmailPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: codeLength) })) + } + } else { + return .fail(error) + } + } + |> mapError { error -> UpdateTwoStepVerificationPasswordError in + if error.errorDescription == "EMAIL_INVALID" { + return .invalidEmail + } else { + return .generic + } + } + } +} + +public enum RequestTwoStepVerificationPasswordRecoveryCodeError { + case generic +} + +public func requestTwoStepVerificationPasswordRecoveryCode(network: Network) -> Signal { + return network.request(Api.functions.auth.requestPasswordRecovery(), automaticFloodWait: false) + |> mapError { _ -> RequestTwoStepVerificationPasswordRecoveryCodeError in + return .generic + } + |> map { result -> String in + switch result { + case let .passwordRecovery(emailPattern): + return emailPattern + } + } +} + +public enum RecoverTwoStepVerificationPasswordError { + case generic + case codeExpired + case limitExceeded + case invalidCode +} + +public func recoverTwoStepVerificationPassword(network: Network, code: String) -> Signal { + return network.request(Api.functions.auth.recoverPassword(code: code), automaticFloodWait: false) + |> mapError { error -> RecoverTwoStepVerificationPasswordError in + if error.errorDescription.hasPrefix("FLOOD_WAIT_") { + return .limitExceeded + } else if error.errorDescription == "PASSWORD_RECOVERY_EXPIRED" { + return .codeExpired + } else if error.errorDescription == "CODE_INVALID" { + return .invalidCode + } else { + return .generic + } + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +public struct TemporaryTwoStepPasswordToken: PostboxCoding, Equatable { + public let token: Data + public let validUntilDate: Int32 + public let requiresBiometrics: Bool + + public init(token: Data, validUntilDate: Int32, requiresBiometrics: Bool) { + self.token = token + self.validUntilDate = validUntilDate + self.requiresBiometrics = requiresBiometrics + } + + public init(decoder: PostboxDecoder) { + self.token = decoder.decodeBytesForKey("t")!.makeData() + self.validUntilDate = decoder.decodeInt32ForKey("d", orElse: 0) + self.requiresBiometrics = decoder.decodeInt32ForKey("b", orElse: 0) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeBytes(MemoryBuffer(data: self.token), forKey: "t") + encoder.encodeInt32(self.validUntilDate, forKey: "d") + encoder.encodeInt32(self.requiresBiometrics ? 1 : 0, forKey: "b") + } + + public static func ==(lhs: TemporaryTwoStepPasswordToken, rhs: TemporaryTwoStepPasswordToken) -> Bool { + return lhs.token == rhs.token && lhs.validUntilDate == rhs.validUntilDate && lhs.requiresBiometrics == rhs.requiresBiometrics + } +} + +public func cachedTwoStepPasswordToken(postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> TemporaryTwoStepPasswordToken? in + let key = ValueBoxKey(length: 1) + key.setUInt8(0, value: 0) + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key)) as? TemporaryTwoStepPasswordToken + } +} + +public func cacheTwoStepPasswordToken(postbox: Postbox, token: TemporaryTwoStepPasswordToken?) -> Signal { + return postbox.transaction { transaction -> Void in + let key = ValueBoxKey(length: 1) + key.setUInt8(0, value: 0) + if let token = token { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key), entry: token, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + } else { + transaction.removeItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key)) + } + } +} + +public func requestTemporaryTwoStepPasswordToken(account: Account, password: String, period: Int32, requiresBiometrics: Bool) -> Signal { + return twoStepAuthData(account.network) + |> mapToSignal { authData -> Signal in + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { + return .fail(MTRpcError(errorCode: 400, errorDescription: "NO_PASSWORD")) + } + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { + return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR")) + } + + let checkPassword: Api.InputCheckPasswordSRP = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + + return account.network.request(Api.functions.account.getTmpPassword(password: checkPassword, period: period), automaticFloodWait: false) + |> map { result -> TemporaryTwoStepPasswordToken in + switch result { + case let .tmpPassword(tmpPassword, validUntil): + return TemporaryTwoStepPasswordToken(token: tmpPassword.makeData(), validUntilDate: validUntil, requiresBiometrics: requiresBiometrics) + } + } + } + |> `catch` { error -> Signal in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .fail(.invalidPassword) + } else { + return .fail(.generic) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Unixtime.swift b/submodules/TelegramCore/TelegramCore/Unixtime.swift new file mode 100644 index 0000000000..090a84723b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Unixtime.swift @@ -0,0 +1,126 @@ +import Foundation + +public struct DateTime { + public let seconds: Int32 // 0 ... 59 + public let minutes: Int32 // 0 ... 59 + public let hours: Int32 // 0 ... 23 + public let dayOfMonth: Int32 // 1 ... 31 + public let month: Int32 // 0 ... 11 + public let year: Int32 // since 1900 + public let dayOfWeek: Int32 // 0 ... 6 + public let dayOfYear: Int32 // 0 ... 365 +} + +private let daysSinceJan1st: [[UInt32]] = +[ + [0,31,59,90,120,151,181,212,243,273,304,334,365], // 365 days, non-leap + [0,31,60,91,121,152,182,213,244,274,305,335,366] // 366 days, leap +] + +public func secondsSinceEpochToDateTime(_ secondsSinceEpoch: Int64) -> DateTime { + var sec: UInt64 + let quadricentennials: UInt32 + var centennials: UInt32 + var quadrennials: UInt32 + var annuals: UInt32 + let year: UInt32 + let leap: UInt32 + let yday: UInt32 + let hour: UInt32 + let min: UInt32 + var month: UInt32 + var mday: UInt32 + let wday: UInt32 + + /* + 400 years: + + 1st hundred, starting immediately after a leap year that's a multiple of 400: + n n n l \ + n n n l } 24 times + ... / + n n n l / + n n n n + + 2nd hundred: + n n n l \ + n n n l } 24 times + ... / + n n n l / + n n n n + + 3rd hundred: + n n n l \ + n n n l } 24 times + ... / + n n n l / + n n n n + + 4th hundred: + n n n l \ + n n n l } 24 times + ... / + n n n l / + n n n L <- 97'th leap year every 400 years + */ + + // Re-bias from 1970 to 1601: + // 1970 - 1601 = 369 = 3*100 + 17*4 + 1 years (incl. 89 leap days) = + // (3*100*(365+24/100) + 17*4*(365+1/4) + 1*365)*24*3600 seconds + sec = UInt64(secondsSinceEpoch) + (11644473600 as UInt64) + + wday = (uint)((sec / 86400 + 1) % 7); // day of week + + // Remove multiples of 400 years (incl. 97 leap days) + quadricentennials = UInt32((UInt64(sec) / (12622780800 as UInt64))) // 400*365.2425*24*3600 + sec %= 12622780800 as UInt64 + + // Remove multiples of 100 years (incl. 24 leap days), can't be more than 3 + // (because multiples of 4*100=400 years (incl. leap days) have been removed) + centennials = UInt32(UInt64(sec) / (3155673600 as UInt64)) // 100*(365+24/100)*24*3600 + if centennials > 3 { + centennials = 3 + } + sec -= UInt64(centennials) * (3155673600 as UInt64) + + // Remove multiples of 4 years (incl. 1 leap day), can't be more than 24 + // (because multiples of 25*4=100 years (incl. leap days) have been removed) + quadrennials = UInt32((UInt64(sec) / (126230400 as UInt64))) // 4*(365+1/4)*24*3600 + if quadrennials > 24 { + quadrennials = 24 + } + sec -= UInt64(quadrennials) * (126230400 as UInt64) + + // Remove multiples of years (incl. 0 leap days), can't be more than 3 + // (because multiples of 4 years (incl. leap days) have been removed) + annuals = UInt32(sec / (31536000 as UInt64)) // 365*24*3600 + if annuals > 3 { + annuals = 3 + } + sec -= UInt64(annuals) * (31536000 as UInt64) + + // Calculate the year and find out if it's leap + year = 1601 + quadricentennials * 400 + centennials * 100 + quadrennials * 4 + annuals; + leap = (!(year % UInt32(4) != 0) && ((year % UInt32(100) != 0) || !(year % UInt32(400) != 0))) ? 1 : 0 + + // Calculate the day of the year and the time + yday = UInt32(sec / (86400 as UInt64)) + sec %= 86400; + hour = UInt32(sec / 3600); + sec %= 3600; + min = UInt32(sec / 60); + sec %= 60; + + mday = 1 + month = 1 + while month < 13 { + if (yday < daysSinceJan1st[Int(leap)][Int(month)]) { + mday += yday - daysSinceJan1st[Int(leap)][Int(month - 1)] + break + } + + month += 1 + } + + return DateTime(seconds: Int32(sec), minutes: Int32(min), hours: Int32(hour), dayOfMonth: Int32(mday), month: Int32(month - 1), year: Int32(year - 1900), dayOfWeek: Int32(wday), dayOfYear: Int32(yday)) +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateAccountPeerName.swift b/submodules/TelegramCore/TelegramCore/UpdateAccountPeerName.swift new file mode 100644 index 0000000000..1451038f40 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateAccountPeerName.swift @@ -0,0 +1,55 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func updateAccountPeerName(account: Account, firstName: String, lastName: String) -> Signal { + return account.network.request(Api.functions.account.updateProfile(flags: (1 << 0) | (1 << 1), firstName: firstName, lastName: lastName, about: nil)) + |> map { result -> Api.User? in + return result + } + |> `catch` { _ in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if let result = result { + let peer = TelegramUser(user: result) + updatePeers(transaction: transaction, peers: [peer], update: { $1 }) + } + } + } +} + +public enum UpdateAboutError { + case generic +} + + +public func updateAbout(account: Account, about: String?) -> Signal { + return account.network.request(Api.functions.account.updateProfile(flags: about == nil ? 0 : (1 << 2), firstName: nil, lastName: nil, about: about)) + |> mapError { _ -> UpdateAboutError in + return .generic + } + |> mapToSignal { apiUser -> Signal in + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([account.peerId]), update: { _, current in + if let current = current as? CachedUserData { + return current.withUpdatedAbout(about) + } else { + return current + } + }) + } |> mapError { _ -> UpdateAboutError in return .generic } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift b/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift new file mode 100644 index 0000000000..f21684ad0b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift @@ -0,0 +1,388 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +func fetchAndUpdateSupplementalCachedPeerData(peerId: PeerId, network: Network, postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + let cachedData = transaction.getPeerCachedData(peerId: peerId) + + if let cachedData = cachedData as? CachedUserData { + if cachedData.peerStatusSettings != nil { + return .complete() + } + } else if let cachedData = cachedData as? CachedGroupData { + if cachedData.peerStatusSettings != nil { + return .complete() + } + } else if let cachedData = cachedData as? CachedChannelData { + if cachedData.peerStatusSettings != nil { + return .complete() + } + } else if let cachedData = cachedData as? CachedSecretChatData { + if cachedData.peerStatusSettings != nil { + return .complete() + } + } + + if peerId.namespace == Namespaces.Peer.SecretChat { + return postbox.transaction { transaction -> Void in + var peerStatusSettings: PeerStatusSettings + if let peer = transaction.getPeer(peerId), let associatedPeerId = peer.associatedPeerId, !transaction.isPeerContact(peerId: associatedPeerId) { + if let peer = peer as? TelegramSecretChat, case .creator = peer.role { + peerStatusSettings = PeerStatusSettings() + peerStatusSettings = [] + } else { + peerStatusSettings = PeerStatusSettings() + peerStatusSettings.insert(.canReport) + } + } else { + peerStatusSettings = PeerStatusSettings() + peerStatusSettings = [] + } + + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in + if let current = current as? CachedSecretChatData { + return current.withUpdatedPeerStatusSettings(peerStatusSettings) + } else { + return CachedSecretChatData(peerStatusSettings: peerStatusSettings) + } + }) + } + } else if let inputPeer = apiInputPeer(peer) { + return network.request(Api.functions.messages.getPeerSettings(peer: inputPeer)) + |> retryRequest + |> mapToSignal { peerSettings -> Signal in + let peerStatusSettings = PeerStatusSettings(apiSettings: peerSettings) + + return postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + switch peerId.namespace { + case Namespaces.Peer.CloudUser: + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + case Namespaces.Peer.CloudGroup: + let previous: CachedGroupData + if let current = current as? CachedGroupData { + previous = current + } else { + previous = CachedGroupData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + case Namespaces.Peer.CloudChannel: + let previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + return previous.withUpdatedPeerStatusSettings(peerStatusSettings) + default: + break + } + return current + }) + } + } + } else { + return .complete() + } + } else { + return .complete() + } + } |> switchToLatest +} + +func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId: PeerId, network: Network, postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> (Api.InputUser?, Peer?) in + if peerId == accountPeerId { + return (.inputUserSelf, transaction.getPeer(peerId)) + } else { + let peer = transaction.getPeer(peerId) + return (peer.flatMap(apiInputUser), peer) + } + } + |> mapToSignal { inputUser, maybePeer -> Signal in + if let inputUser = inputUser { + return network.request(Api.functions.users.getFullUser(id: inputUser)) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + switch result { + case let .userFull(userFull): + let telegramUser = TelegramUser(user: userFull.user) + updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in + return updated + }) + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFull.notifySettings)]) + if let presence = TelegramUserPresence(apiUser: userFull.user) { + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: [telegramUser.id: presence]) + } + } + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in + let previous: CachedUserData + if let current = current as? CachedUserData { + previous = current + } else { + previous = CachedUserData() + } + switch result { + case let .userFull(userFull): + let botInfo = userFull.botInfo.flatMap(BotInfo.init(apiBotInfo:)) + let isBlocked = (userFull.flags & (1 << 0)) != 0 + let callsAvailable = (userFull.flags & (1 << 4)) != 0 + let callsPrivate = (userFull.flags & (1 << 5)) != 0 + let canPinMessages = (userFull.flags & (1 << 7)) != 0 + let pinnedMessageId = userFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) + + let peerStatusSettings = PeerStatusSettings(apiSettings: userFull.settings) + + return previous.withUpdatedAbout(userFull.about).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFull.commonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedCallsAvailable(callsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId) + } + }) + } + } + } else if peerId.namespace == Namespaces.Peer.CloudGroup { + return network.request(Api.functions.messages.getFullChat(chatId: peerId.id)) + |> retryRequest + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + switch result { + case let .chatFull(fullChat, chats, users): + switch fullChat { + case let .chatFull(chatFull): + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: chatFull.notifySettings)]) + case .channelFull: + break + } + + switch fullChat { + case let .chatFull(chatFull): + var botInfos: [CachedPeerBotInfo] = [] + for botInfo in chatFull.botInfo ?? [] { + switch botInfo { + case let .botInfo(userId, _, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + let parsedBotInfo = BotInfo(apiBotInfo: botInfo) + botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + } + } + let participants = CachedGroupParticipants(apiParticipants: chatFull.participants) + let exportedInvitation = ExportedInvitation(apiExportedInvite: chatFull.exportedInvite) + let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + var flags = CachedGroupFlags() + if (chatFull.flags & 1 << 7) != 0 { + flags.insert(.canChangeUsername) + } + + transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in + let previous: CachedGroupData + if let current = current as? CachedGroupData { + previous = current + } else { + previous = CachedGroupData() + } + + return previous.withUpdatedParticipants(participants) + .withUpdatedExportedInvitation(exportedInvitation) + .withUpdatedBotInfos(botInfos) + .withUpdatedPinnedMessageId(pinnedMessageId) + .withUpdatedAbout(chatFull.about) + .withUpdatedFlags(flags) + }) + case .channelFull: + break + } + } + } + } + } else if let inputChannel = maybePeer.flatMap(apiInputChannel) { + return network.request(Api.functions.channels.getFullChannel(channel: inputChannel)) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorDescription == "CHANNEL_PRIVATE" { + return .single(nil) + } + return .complete() + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + if let result = result { + switch result { + case let .chatFull(fullChat, chats, users): + switch fullChat { + case let .channelFull(channelFull): + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: channelFull.notifySettings)]) + case .chatFull: + break + } + + switch fullChat { + case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, pts): + var channelFlags = CachedChannelFlags() + if (flags & (1 << 3)) != 0 { + channelFlags.insert(.canDisplayParticipants) + } + if (flags & (1 << 6)) != 0 { + channelFlags.insert(.canChangeUsername) + } + if (flags & (1 << 10)) == 0 { + channelFlags.insert(.preHistoryEnabled) + } + if (flags & (1 << 12)) != 0 { + channelFlags.insert(.canViewStats) + } + if (flags & (1 << 7)) != 0 { + channelFlags.insert(.canSetStickerSet) + } + + let linkedDiscussionPeerId: PeerId? + + if let linkedChatId = linkedChatId, linkedChatId != 0 { + linkedDiscussionPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: linkedChatId) + } else { + linkedDiscussionPeerId = nil + } + + var botInfos: [CachedPeerBotInfo] = [] + for botInfo in apiBotInfos { + switch botInfo { + case let .botInfo(userId, _, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + let parsedBotInfo = BotInfo(apiBotInfo: botInfo) + botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + } + } + + var pinnedMessageId: MessageId? + if let pinnedMsgId = pinnedMsgId { + pinnedMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: pinnedMsgId) + } + + var minAvailableMessageId: MessageId? + if let minAvailableMsgId = minAvailableMsgId { + minAvailableMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minAvailableMsgId) + + if let pinnedMsgId = pinnedMsgId, pinnedMsgId < minAvailableMsgId { + pinnedMessageId = nil + } + } + + var migrationReference: ChannelMigrationReference? + if let migratedFromChatId = migratedFromChatId, let migratedFromMaxId = migratedFromMaxId { + migrationReference = ChannelMigrationReference(maxMessageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: migratedFromChatId), namespace: Namespaces.Message.Cloud, id: migratedFromMaxId)) + } + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + let stickerPack: StickerPackCollectionInfo? = stickerSet.flatMap { apiSet -> StickerPackCollectionInfo in + let namespace: ItemCollectionId.Namespace + switch apiSet { + case let .stickerSet(flags, _, _, _, _, _, _, _, _, _): + if (flags & (1 << 3)) != 0 { + namespace = Namespaces.ItemCollection.CloudMaskPacks + } else { + namespace = Namespaces.ItemCollection.CloudStickerPacks + } + } + + return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace) + } + + var minAvailableMessageIdUpdated = false + transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in + var previous: CachedChannelData + if let current = current as? CachedChannelData { + previous = current + } else { + previous = CachedChannelData() + } + + previous = previous.withUpdatedIsNotAccessible(false) + + minAvailableMessageIdUpdated = previous.minAvailableMessageId != minAvailableMessageId + + return previous.withUpdatedFlags(channelFlags) + .withUpdatedAbout(about) + .withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount)) + .withUpdatedExportedInvitation(ExportedInvitation(apiExportedInvite: apiExportedInvite)) + .withUpdatedBotInfos(botInfos) + .withUpdatedPinnedMessageId(pinnedMessageId) + .withUpdatedStickerPack(stickerPack) + .withUpdatedMinAvailableMessageId(minAvailableMessageId) + .withUpdatedMigrationReference(migrationReference) + .withUpdatedLinkedDiscussionPeerId(linkedDiscussionPeerId) + }) + + if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated { + transaction.deleteMessagesInRange(peerId: peerId, namespace: minAvailableMessageId.namespace, minId: 1, maxId: minAvailableMessageId.id) + } + case .chatFull: + break + } + } + } else { + transaction.updatePeerCachedData(peerIds: [peerId], update: { _, _ in + var updated = CachedChannelData() + updated = updated.withUpdatedIsNotAccessible(true) + return updated + }) + } + } + } + } else { + return .complete() + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateContactName.swift b/submodules/TelegramCore/TelegramCore/UpdateContactName.swift new file mode 100644 index 0000000000..c6a4ad67d5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateContactName.swift @@ -0,0 +1,44 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum UpdateContactNameError { + case generic +} + +public func updateContactName(account: Account, peerId: PeerId, firstName: String, lastName: String) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) as? TelegramUser, let phone = peer.phone, !phone.isEmpty { + return account.network.request(Api.functions.contacts.importContacts(contacts: [Api.InputContact.inputPhoneContact(clientId: 1, phone: phone, firstName: firstName, lastName: lastName)])) + |> mapError { _ -> UpdateContactNameError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + switch result { + case let .importedContacts(_, _, _, users): + if let first = users.first { + let user = TelegramUser(user: first) + updatePeers(transaction: transaction, peers: [user], update: { _, updated in + return updated + }) + } + } + } |> mapError { _ -> UpdateContactNameError in return .generic } + } + } else { + return .fail(.generic) + } + } |> mapError { _ -> UpdateContactNameError in return .generic } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateGroup.swift b/submodules/TelegramCore/TelegramCore/UpdateGroup.swift new file mode 100644 index 0000000000..e2f829ac05 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateGroup.swift @@ -0,0 +1,221 @@ +import Foundation + +enum UpdateGroup { + case withPts(updates: [Api.Update], users: [Api.User], chats: [Api.Chat]) + case withQts(updates: [Api.Update], users: [Api.User], chats: [Api.Chat]) + case withSeq(updates: [Api.Update], seqRange: (Int32, Int32), date: Int32, users: [Api.User], chats: [Api.Chat]) + case withDate(updates: [Api.Update], date: Int32, users: [Api.User], chats: [Api.Chat]) + case reset + case updatePts(pts: Int32, ptsCount: Int32) + case updateChannelPts(channelId: Int32, pts: Int32, ptsCount: Int32) + + var updates: [Api.Update] { + switch self { + case let .withPts(updates, _, _): + return updates + case let .withDate(updates, _, _, _): + return updates + case let .withQts(updates, _, _): + return updates + case let .withSeq(updates, _, _, _, _): + return updates + case .reset, .updatePts, .updateChannelPts: + return [] + } + } + + var users: [Api.User] { + switch self { + case let .withPts(_, users, _): + return users + case let .withDate(_, _, users, _): + return users + case let .withQts(_, users, _): + return users + case let .withSeq(_, _, _, users, _): + return users + case .reset, .updatePts, .updateChannelPts: + return [] + } + } + + var chats: [Api.Chat] { + switch self { + case let .withPts(_, _, chats): + return chats + case let .withDate(_, _, _, chats): + return chats + case let .withQts(_, _, chats): + return chats + case let .withSeq(_, _, _, _, chats): + return chats + case .reset, .updatePts, .updateChannelPts: + return [] + } + } +} + +func apiUpdatePtsRange(_ update: Api.Update) -> (Int32, Int32)? { + switch update { + case let .updateDeleteMessages(_, pts, ptsCount): + return (pts, ptsCount) + case let .updateNewMessage(_, pts, ptsCount): + return (pts, ptsCount) + case let .updateReadHistoryInbox(_, _, _, _, _, pts, ptsCount): + return (pts, ptsCount) + case let .updateReadHistoryOutbox(_, _, pts, ptsCount): + return (pts, ptsCount) + case let .updateEditMessage(_, pts, ptsCount): + return (pts, ptsCount) + case let .updateReadMessagesContents(_, pts, ptsCount): + return (pts, ptsCount) + case let .updateWebPage(_, pts, ptsCount): + return (pts, ptsCount) + case let .updateFolderPeers(_, pts, ptsCount): + if ptsCount != 0 { + return (pts, ptsCount) + } else { + return nil + } + default: + return nil + } +} + +func apiUpdateQtsRange(_ update: Api.Update) -> (Int32, Int32)? { + switch update { + case let .updateNewEncryptedMessage(_, qts): + return (qts, 1) + case _: + return nil + } +} + +struct PtsUpdate { + let update: Api.Update? + let ptsRange: (Int32, Int32) + let users: [Api.User] + let chats: [Api.Chat] +} + +struct QtsUpdate { + let update: Api.Update + let qtsRange: (Int32, Int32) + let users: [Api.User] + let chats: [Api.Chat] +} + +struct SeqUpdates { + let updates: [Api.Update] + let seqRange: (Int32, Int32) + let date: Int32 + let users: [Api.User] + let chats: [Api.Chat] +} + +func ptsUpdates(_ groups: [UpdateGroup]) -> [PtsUpdate] { + var result: [PtsUpdate] = [] + + for group in groups { + switch group { + case let .withPts(updates, users, chats): + for update in updates { + if let ptsRange = apiUpdatePtsRange(update) { + result.append(PtsUpdate(update: update, ptsRange: ptsRange, users: users, chats: chats)) + } + } + case let .updatePts(pts, ptsCount): + result.append(PtsUpdate(update: nil, ptsRange: (pts, ptsCount), users: [], chats: [])) + case _: + break + } + } + + result.sort(by: { $0.ptsRange.0 < $1.ptsRange.0 }) + + return result +} + +func qtsUpdates(_ groups: [UpdateGroup]) -> [QtsUpdate] { + var result: [QtsUpdate] = [] + + for group in groups { + switch group { + case let .withQts(updates, users, chats): + for update in updates { + if let qtsRange = apiUpdateQtsRange(update) { + result.append(QtsUpdate(update: update, qtsRange: qtsRange, users: users, chats: chats)) + } + } + break + case _: + break + } + } + + result.sort(by: { $0.qtsRange.0 < $1.qtsRange.0 }) + + return result +} + +func seqGroups(_ groups: [UpdateGroup]) -> [SeqUpdates] { + var result: [SeqUpdates] = [] + + for group in groups { + switch group { + case let .withSeq(updates, seqRange, date, users, chats): + result.append(SeqUpdates(updates: updates, seqRange: seqRange, date: date, users: users, chats: chats)) + case _: + break + } + } + + return result +} + +func dateGroups(_ groups: [UpdateGroup]) -> [UpdateGroup] { + var result: [UpdateGroup] = [] + + for group in groups { + switch group { + case .withDate: + result.append(group) + case _: + break + } + } + + return result +} + +func groupUpdates(_ updates: [Api.Update], users: [Api.User], chats: [Api.Chat], date: Int32, seqRange: (Int32, Int32)?) -> [UpdateGroup] { + var updatesWithPts: [Api.Update] = [] + var updatesWithQts: [Api.Update] = [] + var otherUpdates: [Api.Update] = [] + + for update in updates { + if let _ = apiUpdatePtsRange(update) { + updatesWithPts.append(update) + } else if let _ = apiUpdateQtsRange(update) { + updatesWithQts.append(update) + } else { + otherUpdates.append(update) + } + } + + var groups: [UpdateGroup] = [] + if updatesWithPts.count != 0 { + groups.append(.withPts(updates: updatesWithPts, users: users, chats: chats)) + } + if updatesWithQts.count != 0 { + groups.append(.withQts(updates: updatesWithQts, users: users, chats: chats)) + } + + if let seqRange = seqRange { + groups.append(.withSeq(updates: otherUpdates, seqRange: seqRange, date: date, users: users, chats: chats)) + } else { + groups.append(.withDate(updates: otherUpdates, date: date, users: users, chats: chats)) + } + + return groups +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateGroupSpecificStickerset.swift b/submodules/TelegramCore/TelegramCore/UpdateGroupSpecificStickerset.swift new file mode 100644 index 0000000000..4ed49e5737 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateGroupSpecificStickerset.swift @@ -0,0 +1,46 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + + +public enum UpdateGroupSpecificStickersetError { + case generic +} + +public func updateGroupSpecificStickerset(postbox: Postbox, network: Network, peerId: PeerId, info: StickerPackCollectionInfo?) -> Signal { + return postbox.loadedPeerWithId(peerId) + |> introduceError(UpdateGroupSpecificStickersetError.self) + |> mapToSignal { peer -> Signal in + let inputStickerset: Api.InputStickerSet + if let info = info { + inputStickerset = Api.InputStickerSet.inputStickerSetShortName(shortName: info.shortName) + } else { + inputStickerset = Api.InputStickerSet.inputStickerSetEmpty + } + if let inputChannel = apiInputChannel(peer) { + return network.request(Api.functions.channels.setStickers(channel: inputChannel, stickerset: inputStickerset)) + |> mapError { _ -> UpdateGroupSpecificStickersetError in + return .generic + } + |> mapToSignal { value -> Signal in + switch value { + case .boolTrue: + return postbox.transaction { transaction -> Void in + return transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current -> CachedPeerData? in + return (current as? CachedChannelData)?.withUpdatedStickerPack(info) + }) + } + |> introduceError(UpdateGroupSpecificStickersetError.self) + default: + return .complete() + } + } + } + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateMessageMedia.swift b/submodules/TelegramCore/TelegramCore/UpdateMessageMedia.swift new file mode 100644 index 0000000000..7ec82bfdb0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateMessageMedia.swift @@ -0,0 +1,31 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +func updateMessageMedia(transaction: Transaction, id: MediaId, media: Media?) { + let updatedMessageIndices = transaction.updateMedia(id, update: media) + for index in updatedMessageIndices { + transaction.updateMessage(index.id, update: { currentMessage in + var textEntities: [MessageTextEntity]? + for attribute in currentMessage.attributes { + if let attribute = attribute as? TextEntitiesMessageAttribute { + textEntities = attribute.entities + break + } + } + let (tags, _) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: currentMessage.attributes, media: currentMessage.media, textEntities: textEntities) + if tags == currentMessage.tags { + return .skip + } + + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media)) + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateMessageService.swift b/submodules/TelegramCore/TelegramCore/UpdateMessageService.swift new file mode 100644 index 0000000000..25dfadded5 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateMessageService.swift @@ -0,0 +1,99 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +class UpdateMessageService: NSObject, MTMessageService { + var peerId: PeerId! + let pipe: ValuePipe<[UpdateGroup]> = ValuePipe() + var mtProto: MTProto? + + override init() { + super.init() + } + + convenience init(peerId: PeerId) { + self.init() + self.peerId = peerId + } + + func mtProtoWillAdd(_ mtProto: MTProto!) { + self.mtProto = mtProto + } + + func mtProtoDidChangeSession(_ mtProto: MTProto!) { + self.pipe.putNext([.reset]) + } + + func mtProtoServerDidChangeSession(_ mtProto: MTProto!, firstValidMessageId: Int64, otherValidMessageIds: [Any]!) { + self.pipe.putNext([.reset]) + } + + func putNext(_ groups: [UpdateGroup]) { + self.pipe.putNext(groups) + } + + func mtProto(_ mtProto: MTProto!, receivedMessage message: MTIncomingMessage!) { + if let updates = (message.body as? BoxedMessage)?.body as? Api.Updates { + self.addUpdates(updates) + } + } + + func addUpdates(_ updates: Api.Updates) { + switch updates { + case let .updates(updates, users, chats, date, seq): + let groups = groupUpdates(updates, users: users, chats: chats, date: date, seqRange: seq == 0 ? nil : (seq, 1)) + if groups.count != 0 { + self.putNext(groups) + } + case let .updatesCombined(updates, users, chats, date, seqStart, seq): + let groups = groupUpdates(updates, users: users, chats: chats, date: date, seqRange: seq == 0 ? nil : (seq, seq - seqStart)) + if groups.count != 0 { + self.putNext(groups) + } + case let .updateShort(update, date): + let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) + if groups.count != 0 { + self.putNext(groups) + } + case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyToMsgId, entities): + let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: fromId, toId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil) + let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) + let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) + if groups.count != 0 { + self.putNext(groups) + } + case let .updateShortMessage(flags, id, userId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyToMsgId, entities): + let generatedFromId: Int32 + let generatedToId: Api.Peer + if (Int(flags) & 2) != 0 { + generatedFromId = self.peerId.id + generatedToId = Api.Peer.peerUser(userId: userId) + } else { + generatedFromId = userId + generatedToId = Api.Peer.peerUser(userId: self.peerId.id) + } + + let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, toId: generatedToId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil) + let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) + let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) + if groups.count != 0 { + self.putNext(groups) + } + case .updatesTooLong: + self.pipe.putNext([.reset]) + case let .updateShortSentMessage(_, _, pts, ptsCount, _, _, _): + self.pipe.putNext([.updatePts(pts: pts, ptsCount: ptsCount)]) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatePeerChatInterfaceState.swift b/submodules/TelegramCore/TelegramCore/UpdatePeerChatInterfaceState.swift new file mode 100644 index 0000000000..21cbfda09f --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatePeerChatInterfaceState.swift @@ -0,0 +1,24 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func updatePeerChatInterfaceState(account: Account, peerId: PeerId, state: SynchronizeableChatInterfaceState) -> Signal { + return account.postbox.transaction { transaction -> Void in + let currentInputState = (transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState)?.synchronizeableInputState + let updatedInputState = state.synchronizeableInputState + + if currentInputState != updatedInputState { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup { + addSynchronizeChatInputStateOperation(transaction: transaction, peerId: peerId) + } + } + transaction.updatePeerChatInterfaceState(peerId, update: { _ in + return state + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatePeerInfo.swift b/submodules/TelegramCore/TelegramCore/UpdatePeerInfo.swift new file mode 100644 index 0000000000..6753589d01 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatePeerInfo.swift @@ -0,0 +1,99 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum UpdatePeerTitleError { + case generic +} + +public func updatePeerTitle(account: Account, peerId: PeerId, title: String) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.editTitle(channel: inputChannel, title: title)) + |> mapError { _ -> UpdatePeerTitleError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + + return account.postbox.transaction { transaction -> Void in + if let apiChat = apiUpdatesGroups(result).first, let updatedPeer = parseTelegramGroupOrChannel(chat: apiChat) { + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + } + } |> mapError { _ -> UpdatePeerTitleError in return .generic } + } + } else if let peer = peer as? TelegramGroup { + return account.network.request(Api.functions.messages.editChatTitle(chatId: peer.id.id, title: title)) + |> mapError { _ -> UpdatePeerTitleError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + + return account.postbox.transaction { transaction -> Void in + if let apiChat = apiUpdatesGroups(result).first, let updatedPeer = parseTelegramGroupOrChannel(chat: apiChat) { + updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in + return updated + }) + } + } |> mapError { _ -> UpdatePeerTitleError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } |> mapError { _ -> UpdatePeerTitleError in return .generic } |> switchToLatest +} + +public enum UpdatePeerDescriptionError { + case generic +} + +public func updatePeerDescription(account: Account, peerId: PeerId, description: String?) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + if (peer is TelegramChannel || peer is TelegramGroup), let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.messages.editChatAbout(peer: inputPeer, about: description ?? "")) + |> mapError { _ -> UpdatePeerDescriptionError in + return .generic + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Void in + if case .boolTrue = result { + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedChannelData { + return current.withUpdatedAbout(description) + } else if let current = current as? CachedGroupData { + return current.withUpdatedAbout(description) + } else { + return current + } + }) + } + } + |> mapError { _ -> UpdatePeerDescriptionError in return .generic } + } + } else { + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } |> mapError { _ -> UpdatePeerDescriptionError in return .generic } |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatePeers.swift b/submodules/TelegramCore/TelegramCore/UpdatePeers.swift new file mode 100644 index 0000000000..49b41a7529 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatePeers.swift @@ -0,0 +1,138 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +func updatePeerChatInclusionWithMinTimestamp(transaction: Transaction, id: PeerId, minTimestamp: Int32, forceRootGroupIfNotExists: Bool) { + let currentInclusion = transaction.getPeerChatListInclusion(id) + var updatedInclusion: PeerChatListInclusion? + switch currentInclusion { + case let .ifHasMessagesOrOneOf(groupId, pinningIndex, currentMinTimestamp): + let updatedMinTimestamp: Int32 + if let currentMinTimestamp = currentMinTimestamp { + if minTimestamp > currentMinTimestamp { + updatedMinTimestamp = minTimestamp + } else { + updatedMinTimestamp = currentMinTimestamp + } + } else { + updatedMinTimestamp = minTimestamp + } + updatedInclusion = .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: pinningIndex, minTimestamp: updatedMinTimestamp) + default: + if forceRootGroupIfNotExists { + updatedInclusion = .ifHasMessagesOrOneOf(groupId: .root, pinningIndex: nil, minTimestamp: minTimestamp) + } + } + if let updatedInclusion = updatedInclusion { + transaction.updatePeerChatListInclusion(id, inclusion: updatedInclusion) + } +} + +func minTimestampForPeerInclusion(_ peer: Peer) -> Int32? { + if let group = peer as? TelegramGroup { + return group.creationDate + } else if let channel = peer as? TelegramChannel { + return channel.creationDate + } else { + return nil + } +} + +public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?, Peer) -> Peer?) { + transaction.updatePeersInternal(peers, update: { previous, updated in + let peerId = updated.id + + switch peerId.namespace { + case Namespaces.Peer.CloudUser: + break + case Namespaces.Peer.CloudGroup: + if let group = updated as? TelegramGroup { + if group.flags.contains(.deactivated) { + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + } else { + switch group.membership { + case .Member: + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: group.creationDate, forceRootGroupIfNotExists: false) + default: + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + } + } + } else { + assertionFailure() + } + case Namespaces.Peer.CloudChannel: + if let channel = updated as? TelegramChannel { + switch channel.participationStatus { + case .member: + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: channel.creationDate, forceRootGroupIfNotExists: false) + case .left: + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + case .kicked where channel.creationDate == 0: + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + default: + transaction.updatePeerChatListInclusion(peerId, inclusion: .notIncluded) + } + } else { + assertionFailure() + } + case Namespaces.Peer.SecretChat: + if let secretChat = updated as? TelegramSecretChat { + let isActive: Bool + switch secretChat.embeddedState { + case .active, .handshake: + isActive = true + case .terminated: + isActive = false + } + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: secretChat.creationDate, forceRootGroupIfNotExists: isActive) + } else { + assertionFailure() + } + default: + assertionFailure() + break + } + + return update(previous, updated) + }) +} + +func updatePeerPresences(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: PeerPresence]) { + var peerPresences = peerPresences + if peerPresences[accountPeerId] != nil { + peerPresences.removeValue(forKey: accountPeerId) + } + transaction.updatePeerPresencesInternal(presences: peerPresences, merge: { previous, updated in + if let previous = previous as? TelegramUserPresence, let updated = updated as? TelegramUserPresence, previous.lastActivity != updated.lastActivity { + return TelegramUserPresence(status: updated.status, lastActivity: max(previous.lastActivity, updated.lastActivity)) + } + return updated + }) +} + +func updatePeerPresenceLastActivities(transaction: Transaction, accountPeerId: PeerId, activities: [PeerId: Int32]) { + var activities = activities + if activities[accountPeerId] != nil { + activities.removeValue(forKey: accountPeerId) + } + for (peerId, timestamp) in activities { + transaction.updatePeerPresenceInternal(peerId: peerId, update: { previous in + if let previous = previous as? TelegramUserPresence, previous.lastActivity < timestamp { + var updatedStatus = previous.status + switch updatedStatus { + case let .present(until): + if until < timestamp { + updatedStatus = .present(until: timestamp) + } + default: + break + } + return TelegramUserPresence(status: updatedStatus, lastActivity: timestamp) + } + return previous + }) + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatePinnedMessage.swift b/submodules/TelegramCore/TelegramCore/UpdatePinnedMessage.swift new file mode 100644 index 0000000000..a042a6b80c --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatePinnedMessage.swift @@ -0,0 +1,156 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public enum UpdatePinnedMessageError { + case generic +} + +public enum PinnedMessageUpdate { + case pin(id: MessageId, silent: Bool) + case clear +} + +public func requestUpdatePinnedMessage(account: Account, peerId: PeerId, update: PinnedMessageUpdate) -> Signal { + return account.postbox.transaction { transaction -> (Peer?, CachedPeerData?) in + return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId)) + } + |> mapError { _ -> UpdatePinnedMessageError in + return .generic + } + |> mapToSignal { peer, cachedPeerData -> Signal in + guard let peer = peer, let inputPeer = apiInputPeer(peer) else { + return .fail(.generic) + } + if let channel = peer as? TelegramChannel, let inputPeer = apiInputPeer(channel) { + let canManagePin = channel.hasPermission(.pinMessages) + + if canManagePin { + var flags: Int32 = 0 + let messageId: Int32 + switch update { + case let .pin(id, silent): + messageId = id.id + if silent { + flags |= (1 << 0) + } + case .clear: + messageId = 0 + } + + let request = Api.functions.messages.updatePinnedMessage(flags: flags, peer: inputPeer, id: messageId) + + return account.network.request(request) + |> mapError { _ -> UpdatePinnedMessageError in + return .generic + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + return account.postbox.transaction { transaction in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedChannelData { + let pinnedMessageId: MessageId? + switch update { + case let .pin(id, _): + pinnedMessageId = id + case .clear: + pinnedMessageId = nil + } + return current.withUpdatedPinnedMessageId(pinnedMessageId) + } else { + return current + } + }) + } + |> mapError { _ -> UpdatePinnedMessageError in return .generic + } + } + } else { + return .fail(.generic) + } + } else { + var canPin = false + if let group = peer as? TelegramGroup { + switch group.role { + case .creator, .admin: + canPin = true + default: + if let defaultBannedRights = group.defaultBannedRights { + canPin = !defaultBannedRights.flags.contains(.banPinMessages) + } else { + canPin = true + } + } + } else if let _ = peer as? TelegramUser, let cachedPeerData = cachedPeerData as? CachedUserData { + canPin = cachedPeerData.canPinMessages + } + if canPin { + var flags: Int32 = 0 + let messageId: Int32 + switch update { + case let .pin(id, silent): + messageId = id.id + if silent { + flags |= (1 << 0) + } + case .clear: + messageId = 0 + } + + let request = Api.functions.messages.updatePinnedMessage(flags: flags, peer: inputPeer, id: messageId) + + return account.network.request(request) + |> mapError { _ -> UpdatePinnedMessageError in + return .generic + } + |> mapToSignal { updates -> Signal in + account.stateManager.addUpdates(updates) + return account.postbox.transaction { transaction in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let _ = peer as? TelegramGroup { + let current = current as? CachedGroupData ?? CachedGroupData() + let pinnedMessageId: MessageId? + switch update { + case let .pin(id, _): + pinnedMessageId = id + case .clear: + pinnedMessageId = nil + } + return current.withUpdatedPinnedMessageId(pinnedMessageId) + } else if let _ = peer as? TelegramUser { + let current = current as? CachedUserData ?? CachedUserData() + + let pinnedMessageId: MessageId? + switch update { + case let .pin(id, _): + pinnedMessageId = id + case .clear: + pinnedMessageId = nil + } + return current.withUpdatedPinnedMessageId(pinnedMessageId) + } else { + return current + } + }) + } + |> mapError { _ -> UpdatePinnedMessageError in + return .generic + } + } + } else { + return .fail(.generic) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift b/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift new file mode 100644 index 0000000000..a36485ebd0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift @@ -0,0 +1,126 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +struct SecretChatRequestData { + let g: Int32 + let p: MemoryBuffer + let a: MemoryBuffer +} + +func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api.EncryptedChat, requestData: SecretChatRequestData?) { + let currentPeer = transaction.getPeer(chat.peerId) as? TelegramSecretChat + let currentState = transaction.getPeerChatState(chat.peerId) as? SecretChatState + assert((currentPeer == nil) == (currentState == nil)) + switch chat { + case let .encryptedChat(_, _, _, adminId, _, gAOrB, remoteKeyFingerprint): + if let currentPeer = currentPeer, let currentState = currentState, adminId == accountPeerId.id { + if case let .handshake(handshakeState) = currentState.embeddedState, case let .requested(_, p, a) = handshakeState { + let pData = p.makeData() + let aData = a.makeData() + + if !MTCheckIsSafeGAOrB(gAOrB.makeData(), pData) { + var updatedState = currentState + updatedState = updatedState.withUpdatedEmbeddedState(.terminated) + transaction.setPeerChatState(chat.peerId, state: updatedState) + return + } + + var key = MTExp(gAOrB.makeData(), aData, pData)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) + } + } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + var updatedState = currentState + updatedState = updatedState.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretIncomingDecrypted), baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil))) + + updatedState = updatedState.withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) + + updatedState = secretChatAddReportCurrentLayerSupportOperationAndUpdateRequestedLayer(transaction: transaction, peerId: currentPeer.id, state: updatedState) + + transaction.setPeerChatState(currentPeer.id, state: updatedState) + updatePeers(transaction: transaction, peers: [currentPeer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in + return updated + }) + } else { + Logger.shared.log("State", "got encryptedChat, but chat is not in handshake state") + } + } else { + Logger.shared.log("State", "got encryptedChat, but peer or state don't exist or account is not creator") + } + case .encryptedChatDiscarded(_): + if let currentPeer = currentPeer, let currentState = currentState { + let state = currentState.withUpdatedEmbeddedState(.terminated) + let peer = currentPeer.withUpdatedEmbeddedState(state.embeddedState.peerState) + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in return updated }) + transaction.setPeerChatState(peer.id, state: state) + transaction.operationLogRemoveAllEntries(peerId: peer.id, tag: OperationLogTags.SecretOutgoing) + } else { + Logger.shared.log("State", "got encryptedChatDiscarded, but peer doesn't exist") + } + case .encryptedChatEmpty(_): + break + case let .encryptedChatRequested(_, accessHash, date, adminId, participantId, gA): + if currentPeer == nil && participantId == accountPeerId.id { + let state = SecretChatState(role: .participant, embeddedState: .handshake(.accepting), keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil) + + let bBytes = malloc(256)! + let randomStatus = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self)) + let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true) + if randomStatus == 0 { + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: chat.peerId, operation: .initialHandshakeAccept(gA: MemoryBuffer(gA), accessHash: accessHash, b: b), state: state) + transaction.setPeerChatState(chat.peerId, state: updatedState) + + let peer = TelegramSecretChat(id: chat.peerId, creationDate: date, regularPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId), accessHash: accessHash, role: updatedState.role, embeddedState: updatedState.embeddedState.peerState, messageAutoremoveTimeout: nil) + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in return updated }) + transaction.resetIncomingReadStates([peer.id: [ + Namespaces.Message.SecretIncoming: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false), + Namespaces.Message.Local: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false) + ] + ]) + } else { + assertionFailure() + } + } else { + Logger.shared.log("State", "got encryptedChatRequested, but peer already exists or this account is creator") + } + case let .encryptedChatWaiting(_, accessHash, date, adminId, participantId): + if let requestData = requestData, currentPeer == nil && adminId == accountPeerId.id { + let state = SecretChatState(role: .creator, embeddedState: .handshake(.requested(g: requestData.g, p: requestData.p, a: requestData.a)), keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil) + let peer = TelegramSecretChat(id: chat.peerId, creationDate: date, regularPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: participantId), accessHash: accessHash, role: state.role, embeddedState: state.embeddedState.peerState, messageAutoremoveTimeout: nil) + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in return updated }) + transaction.setPeerChatState(peer.id, state: state) + transaction.resetIncomingReadStates([peer.id: [ + Namespaces.Message.SecretIncoming: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false), + Namespaces.Message.Local: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false) + ] + ]) + } else { + Logger.shared.log("State", "got encryptedChatWaiting, but peer already exists or this account is not creator") + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatedAccountPrivacySettings.swift b/submodules/TelegramCore/TelegramCore/UpdatedAccountPrivacySettings.swift new file mode 100644 index 0000000000..e489e3a9f0 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatedAccountPrivacySettings.swift @@ -0,0 +1,233 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func requestAccountPrivacySettings(account: Account) -> Signal { + let lastSeenPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyStatusTimestamp)) + let groupPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyChatInvite)) + let voiceCallPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyPhoneCall)) + let voiceCallP2P = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyPhoneP2P)) + let profilePhotoPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyProfilePhoto)) + let forwardPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyForwards)) + let phoneNumberPrivacy = account.network.request(Api.functions.account.getPrivacy(key: .inputPrivacyKeyPhoneNumber)) + let autoremoveTimeout = account.network.request(Api.functions.account.getAccountTTL()) + return combineLatest(lastSeenPrivacy, groupPrivacy, voiceCallPrivacy, voiceCallP2P, profilePhotoPrivacy, forwardPrivacy, phoneNumberPrivacy, autoremoveTimeout) + |> `catch` { _ in + return .complete() + } + |> mapToSignal { lastSeenPrivacy, groupPrivacy, voiceCallPrivacy, voiceCallP2P, profilePhotoPrivacy, forwardPrivacy, phoneNumberPrivacy, autoremoveTimeout -> Signal in + let accountTimeoutSeconds: Int32 + switch autoremoveTimeout { + case let .accountDaysTTL(days): + accountTimeoutSeconds = days * 24 * 60 * 60 + } + + let lastSeenRules: [Api.PrivacyRule] + let groupRules: [Api.PrivacyRule] + let voiceRules: [Api.PrivacyRule] + let voiceP2PRules: [Api.PrivacyRule] + let profilePhotoRules: [Api.PrivacyRule] + let forwardRules: [Api.PrivacyRule] + let phoneNumberRules: [Api.PrivacyRule] + var apiUsers: [Api.User] = [] + var apiChats: [Api.Chat] = [] + + switch lastSeenPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + lastSeenRules = rules + } + + switch groupPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + groupRules = rules + } + + switch voiceCallPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + voiceRules = rules + } + + switch voiceCallP2P { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + voiceP2PRules = rules + } + + switch profilePhotoPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + profilePhotoRules = rules + } + + switch forwardPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + forwardRules = rules + } + + switch phoneNumberPrivacy { + case let .privacyRules(rules, chats, users): + apiUsers.append(contentsOf: users) + apiChats.append(contentsOf: chats) + phoneNumberRules = rules + } + + var peers: [SelectivePrivacyPeer] = [] + for user in apiUsers { + peers.append(SelectivePrivacyPeer(peer: TelegramUser(user: user), participantCount: nil)) + } + for chat in apiChats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + var participantCount: Int32? = nil + switch chat { + case let .channel(channel): + participantCount = channel.participantsCount + default: + break + } + peers.append(SelectivePrivacyPeer(peer: peer, participantCount: participantCount)) + } + } + var peerMap: [PeerId: SelectivePrivacyPeer] = [:] + for peer in peers { + peerMap[peer.peer.id] = peer + } + + return account.postbox.transaction { transaction -> AccountPrivacySettings in + updatePeers(transaction: transaction, peers: peers.map { $0.peer }, update: { _, updated in + return updated + }) + + return AccountPrivacySettings(presence: SelectivePrivacySettings(apiRules: lastSeenRules, peers: peerMap), groupInvitations: SelectivePrivacySettings(apiRules: groupRules, peers: peerMap), voiceCalls: SelectivePrivacySettings(apiRules: voiceRules, peers: peerMap), voiceCallsP2P: SelectivePrivacySettings(apiRules: voiceP2PRules, peers: peerMap), profilePhoto: SelectivePrivacySettings(apiRules: profilePhotoRules, peers: peerMap), forwards: SelectivePrivacySettings(apiRules: forwardRules, peers: peerMap), phoneNumber: SelectivePrivacySettings(apiRules: phoneNumberRules, peers: peerMap), accountRemovalTimeout: accountTimeoutSeconds) + } + } +} + +public func updateAccountRemovalTimeout(account: Account, timeout: Int32) -> Signal { + return account.network.request(Api.functions.account.setAccountTTL(ttl: .accountDaysTTL(days: timeout / (24 * 60 * 60)))) + |> retryRequest + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +public enum UpdateSelectiveAccountPrivacySettingsType { + case presence + case groupInvitations + case voiceCalls + case voiceCallsP2P + case profilePhoto + case forwards + case phoneNumber + + var apiKey: Api.InputPrivacyKey { + switch self { + case .presence: + return .inputPrivacyKeyStatusTimestamp + case .groupInvitations: + return .inputPrivacyKeyChatInvite + case .voiceCalls: + return .inputPrivacyKeyPhoneCall + case .voiceCallsP2P: + return .inputPrivacyKeyPhoneP2P + case .profilePhoto: + return .inputPrivacyKeyProfilePhoto + case .forwards: + return .inputPrivacyKeyForwards + case .phoneNumber: + return .inputPrivacyKeyPhoneNumber + } + } +} + +private func apiInputUsers(transaction: Transaction, peerIds: [PeerId]) -> [Api.InputUser] { + var result: [Api.InputUser] = [] + for peerId in peerIds { + if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { + result.append(inputUser) + } + } + return result +} + +private func apiUserAndGroupIds(peerIds: [PeerId: SelectivePrivacyPeer]) -> (users: [PeerId], groups: [PeerId]) { + var users: [PeerId] = [] + var groups: [PeerId] = [] + for (peerId, _) in peerIds { + if peerId.namespace == Namespaces.Peer.CloudUser { + users.append(peerId) + } else if peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel { + groups.append(peerId) + } + } + return (users, groups) +} + +public func updateSelectiveAccountPrivacySettings(account: Account, type: UpdateSelectiveAccountPrivacySettingsType, settings: SelectivePrivacySettings) -> Signal { + return account.postbox.transaction { transaction -> Signal in + var rules: [Api.InputPrivacyRule] = [] + switch settings { + case let .disableEveryone(enableFor): + let enablePeers = apiUserAndGroupIds(peerIds: enableFor) + + if !enablePeers.users.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowUsers(users: apiInputUsers(transaction: transaction, peerIds: enablePeers.users))) + } + if !enablePeers.groups.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowChatParticipants(chats: enablePeers.groups.map({ $0.id }))) + } + + rules.append(Api.InputPrivacyRule.inputPrivacyValueDisallowAll) + case let .enableContacts(enableFor, disableFor): + let enablePeers = apiUserAndGroupIds(peerIds: enableFor) + let disablePeers = apiUserAndGroupIds(peerIds: disableFor) + + if !enablePeers.users.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowUsers(users: apiInputUsers(transaction: transaction, peerIds: enablePeers.users))) + } + if !enablePeers.groups.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowChatParticipants(chats: enablePeers.groups.map({ $0.id }))) + } + + if !disablePeers.users.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueDisallowUsers(users: apiInputUsers(transaction: transaction, peerIds: disablePeers.users))) + } + if !disablePeers.groups.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueDisallowChatParticipants(chats: disablePeers.groups.map({ $0.id }))) + } + + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowContacts) + case let .enableEveryone(disableFor): + let disablePeers = apiUserAndGroupIds(peerIds: disableFor) + + if !disablePeers.users.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueDisallowUsers(users: apiInputUsers(transaction: transaction, peerIds: disablePeers.users))) + } + if !disablePeers.groups.isEmpty { + rules.append(Api.InputPrivacyRule.inputPrivacyValueDisallowChatParticipants(chats: disablePeers.groups.map({ $0.id }))) + } + + rules.append(Api.InputPrivacyRule.inputPrivacyValueAllowAll) + } + return account.network.request(Api.functions.account.setPrivacy(key: type.apiKey, rules: rules)) + |> retryRequest + |> mapToSignal { _ -> Signal in + return .complete() + } + } + |> switchToLatest +} diff --git a/submodules/TelegramCore/TelegramCore/UpdatesApiUtils.swift b/submodules/TelegramCore/TelegramCore/UpdatesApiUtils.swift new file mode 100644 index 0000000000..557472cedf --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UpdatesApiUtils.swift @@ -0,0 +1,565 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +private func collectPreCachedResources(for photo: Api.Photo) -> [(MediaResource, Data)]? { + switch photo { + case let .photo(_, id, accessHash, fileReference, _, sizes, dcId): + for size in sizes { + switch size { + case let .photoCachedSize(type, location, _, _, bytes): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudPhotoSizeMediaResource(datacenterId: dcId, photoId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData()) + let data = bytes.makeData() + return [(resource, data)] + } + default: + break + } + } + return nil + case .photoEmpty: + return nil + } +} + +private func collectPreCachedResources(for document: Api.Document) -> [(MediaResource, Data)]? { + switch document { + case let .document(_, id, accessHash, fileReference, _, _, _, thumbs, dcId, _): + if let thumbs = thumbs { + for thumb in thumbs { + switch thumb { + case let .photoCachedSize(type, location, _, _, bytes): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudDocumentSizeMediaResource(datacenterId: dcId, documentId: id, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference.makeData()) + let data = bytes.makeData() + return [(resource, data)] + } + default: + break + } + } + } + default: + break + } + return nil +} + +extension Api.MessageMedia { + var preCachedResources: [(MediaResource, Data)]? { + switch self { + case let .messageMediaPhoto(_, photo, _): + if let photo = photo { + return collectPreCachedResources(for: photo) + } else { + return nil + } + case let .messageMediaDocument(_, document, _): + if let document = document { + return collectPreCachedResources(for: document) + } + return nil + case let .messageMediaWebPage(webPage): + var result: [(MediaResource, Data)]? + switch webPage { + case let .webPage(content): + if let photo = content.photo { + if let photoResult = collectPreCachedResources(for: photo) { + if result == nil { + result = [] + } + result!.append(contentsOf: photoResult) + } + } + if let file = content.document { + if let fileResult = collectPreCachedResources(for: file) { + if result == nil { + result = [] + } + result!.append(contentsOf: fileResult) + } + } + default: + break + } + return result + default: + return nil + } + } +} + +extension Api.Message { + var rawId: Int32 { + switch self { + case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + return id + case let .messageEmpty(id): + return id + case let .messageService(_, id, _, _, _, _, _): + return id + } + } + + var id: MessageId? { + switch self { + case let .message(flags, id, fromId, toId, _, _, _, _, _, _, _, _, _, _, _, _): + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id) + case .messageEmpty: + return nil + case let .messageService(flags, id, fromId, toId, _, _, _): + let peerId: PeerId + switch toId { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: (flags & Int32(2)) != 0 ? userId : (fromId ?? userId)) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + + return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id) + } + } + + var timestamp: Int32? { + switch self { + case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _): + return date + case let .messageService(_, _, _, _, _, date, _): + return date + case .messageEmpty: + return nil + } + } + + var preCachedResources: [(MediaResource, Data)]? { + switch self { + case let .message(_, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _): + return media?.preCachedResources + default: + return nil + } + } +} + +extension Api.Chat { + var peerId: PeerId { + switch self { + case let .chat(chat): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chat.id) + case let .chatEmpty(id): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: id) + case let .chatForbidden(id, _): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: id) + case let .channel(channel): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channel.id) + case let .channelForbidden(_, id, _, _, _): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: id) + } + } +} + +extension Api.User { + var peerId: PeerId { + switch self { + case .user(_, let id, _, _, _, _, _, _, _, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: id) + case let .userEmpty(id): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: id) + } + } +} + +extension Api.Peer { + var peerId: PeerId { + switch self { + case let .peerChannel(channelId): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + case let .peerChat(chatId): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerUser(userId): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + } + } +} + +extension Api.Dialog { + var peerId: PeerId? { + switch self { + case let .dialog(_, peer, _, _, _, _, _, _, _, _, _): + return peer.peerId + case .dialogFolder: + return nil + } + } +} + +extension Api.Update { + var rawMessageId: Int32? { + switch self { + case let .updateMessageID(id, _): + return id + case let .updateNewMessage(message, _, _): + return message.rawId + case let .updateNewChannelMessage(message, _, _): + return message.rawId + default: + return nil + } + } + + var updatedRawMessageId: (Int64, Int32)? { + switch self { + case let .updateMessageID(id, randomId): + return (randomId, id) + default: + return nil + } + } + + var messageId: MessageId? { + switch self { + case let .updateNewMessage(message, _, _): + return message.id + case let .updateNewChannelMessage(message, _, _): + return message.id + default: + return nil + } + } + + var message: Api.Message? { + switch self { + case let .updateNewMessage(message, _, _): + return message + case let .updateNewChannelMessage(message, _, _): + return message + case let .updateEditMessage(message, _, _): + return message + case let .updateEditChannelMessage(message, _, _): + return message + default: + return nil + } + } + + var peerIds: [PeerId] { + switch self { + case let .updateChannel(channelId): + return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] + case let .updateChannelTooLong(_, channelId, _): + return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] + case let .updateChatParticipantAdd(chatId, userId, inviterId, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId)] + case let .updateChatParticipantAdmin(chatId, userId, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] + case let .updateChatParticipantDelete(chatId, userId, _): + return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] + case let .updateChatParticipants(participants): + switch participants { + case let .chatParticipants(chatId, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)] + case let .chatParticipantsForbidden(_, chatId, _): + return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)] + } + case let .updateDeleteChannelMessages(channelId, _, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] + case let .updateNewChannelMessage(message, _, _): + return apiMessagePeerIds(message) + case let .updateEditChannelMessage(message, _, _): + return apiMessagePeerIds(message) + case let .updateChannelWebPage(channelId, _, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] + case let .updateNewMessage(message, _, _): + return apiMessagePeerIds(message) + case let .updateEditMessage(message, _, _): + return apiMessagePeerIds(message) + case let .updateReadChannelInbox(_, _, channelId, _, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)] + case let .updateNotifySettings(peer, _): + switch peer { + case let .notifyPeer(peer): + return [peer.peerId] + default: + return [] + } + case let .updateUserName(userId, _, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] + case let .updateUserPhone(userId, _): + return [PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] + case let .updateUserPhoto(userId, _, _, _): + return [PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)] + case let .updateServiceNotification(_, inboxDate, _, _, _, _): + if let _ = inboxDate { + return [PeerId(namespace: Namespaces.Peer.CloudUser, id: 777000)] + } else { + return [] + } + case let .updateDraftMessage(peer: peer, draft: _): + return [peer.peerId] + default: + return [] + } + } + + var associatedMessageIds: [MessageId]? { + switch self { + case let .updateNewMessage(message, _, _): + return apiMessageAssociatedMessageIds(message) + case let .updateNewChannelMessage(message, _, _): + return apiMessageAssociatedMessageIds(message) + case let .updateEditChannelMessage(message, _, _): + return apiMessageAssociatedMessageIds(message) + default: + break + } + return nil + } + + var channelPts: Int32? { + switch self { + case let .updateNewChannelMessage(_, pts, _): + return pts + case let .updateEditChannelMessage(_, pts, _): + return pts + default: + return nil + } + } +} + +extension Api.Updates { + var rawMessageIds: [Int32] { + switch self { + case let .updates(updates, _, _, _, _): + var result: [Int32] = [] + for update in updates { + if let id = update.rawMessageId { + result.append(id) + } + } + return result + case let .updatesCombined(updates, _, _, _, _, _): + var result: [Int32] = [] + for update in updates { + if let id = update.rawMessageId { + result.append(id) + } + } + return result + case let .updateShort(update, _): + if let id = update.rawMessageId { + return [id] + } else { + return [] + } + case let .updateShortSentMessage(_, id, _, _, _, _, _): + return [id] + case .updatesTooLong: + return [] + case let .updateShortMessage(_, id, _, _, _, _, _, _, _, _, _): + return [id] + case let .updateShortChatMessage(_, id, _, _, _, _, _, _, _, _, _, _): + return [id] + } + } + + var messageIds: [MessageId] { + switch self { + case let .updates(updates, _, _, _, _): + var result: [MessageId] = [] + for update in updates { + if let id = update.messageId { + result.append(id) + } + } + return result + case let .updatesCombined(updates, _, _, _, _, _): + var result: [MessageId] = [] + for update in updates { + if let id = update.messageId { + result.append(id) + } + } + return result + case let .updateShort(update, _): + if let id = update.messageId { + return [id] + } else { + return [] + } + case .updateShortSentMessage: + return [] + case .updatesTooLong: + return [] + case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _): + return [MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), namespace: Namespaces.Message.Cloud, id: id)] + case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _): + return [MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), namespace: Namespaces.Message.Cloud, id: id)] + } + } + + var updatedRawMessageIds: [Int64: Int32] { + switch self { + case let .updates(updates, _, _, _, _): + var result: [Int64: Int32] = [:] + for update in updates { + if let (randomId, id) = update.updatedRawMessageId { + result[randomId] = id + } + } + return result + case let .updatesCombined(updates, _, _, _, _, _): + var result: [Int64: Int32] = [:] + for update in updates { + if let (randomId, id) = update.updatedRawMessageId { + result[randomId] = id + } + } + return result + case let .updateShort(update, _): + if let (randomId, id) = update.updatedRawMessageId { + return [randomId: id] + } else { + return [:] + } + case .updateShortSentMessage: + return [:] + case .updatesTooLong: + return [:] + case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _): + return [:] + case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _): + return [:] + } + } +} + +extension Api.Updates { + var messages: [Api.Message] { + switch self { + case let .updates(updates, _, _, _, _): + var result: [Api.Message] = [] + for update in updates { + if let message = update.message { + result.append(message) + } + } + return result + case let .updatesCombined(updates, _, _, _, _, _): + var result: [Api.Message] = [] + for update in updates { + if let message = update.message { + result.append(message) + } + } + return result + case let .updateShort(update, _): + if let message = update.message { + return [message] + } else { + return [] + } + default: + return [] + } + } + + var channelPts: Int32? { + switch self { + case let .updates(updates, _, _, _, _): + var result: Int32? + for update in updates { + if let channelPts = update.channelPts { + if result == nil || channelPts > result! { + result = channelPts + } + } + } + return result + case let .updatesCombined(updates, _, _, _, _, _): + var result: Int32? + for update in updates { + if let channelPts = update.channelPts { + if result == nil || channelPts > result! { + result = channelPts + } + } + } + return result + case let .updateShort(update, _): + if let channelPts = update.channelPts { + return channelPts + } else { + return nil + } + default: + return nil + } + } +} + +extension Api.Updates { + var chats: [Api.Chat] { + switch self { + case let .updates(_, _, chats, _, _): + var result: [Api.Chat] = [] + for chat in chats { + result.append(chat) + } + return result + case let .updatesCombined(_, _, chats, _, _, _): + var result: [Api.Chat] = [] + for chat in chats { + result.append(chat) + } + return result + default: + return [] + } + } +} + +extension Api.EncryptedChat { + var peerId: PeerId { + switch self { + case let .encryptedChat(id, _, _, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: id) + case let .encryptedChatDiscarded(id): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: id) + case let .encryptedChatEmpty(id): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: id) + case let .encryptedChatRequested(id, _, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: id) + case let .encryptedChatWaiting(id, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: id) + } + } +} + +extension Api.EncryptedMessage { + var peerId: PeerId { + switch self { + case let .encryptedMessage(_, chatId, _, _, _): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId) + case let .encryptedMessageService(_, chatId, _, _): + return PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/UploadSecureIdFile.swift b/submodules/TelegramCore/TelegramCore/UploadSecureIdFile.swift new file mode 100644 index 0000000000..12ccb34bc6 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/UploadSecureIdFile.swift @@ -0,0 +1,137 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public struct UploadedSecureIdFile: Equatable { + let id: Int64 + let parts: Int32 + let md5Checksum: String + public let fileHash: Data + let encryptedSecret: Data +} + +public enum UploadSecureIdFileResult { + case progress(Float) + case result(UploadedSecureIdFile, Data) +} + +public enum UploadSecureIdFileError { + case generic +} + +private struct EncryptedSecureIdFile { + let data: Data + let hash: Data + let encryptedSecret: Data +} + +private func encryptedSecureIdFile(context: SecureIdAccessContext, data: Data) -> EncryptedSecureIdFile? { + guard let fileSecret = generateSecureSecretData() else { + return nil + } + + let paddedFileData = paddedSecureIdData(data) + let fileHash = sha256Digest(paddedFileData) + let fileSecretHash = sha512Digest(fileSecret + fileHash) + let fileKey = fileSecretHash.subdata(in: 0 ..< 32) + let fileIv = fileSecretHash.subdata(in: 32 ..< (32 + 16)) + guard let encryptedFileData = encryptSecureData(key: fileKey, iv: fileIv, data: paddedFileData, decrypt: false) else { + return nil + } + + let secretHash = sha512Digest(context.secret + fileHash) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + guard let encryptedSecretData = encryptSecureData(key: secretKey, iv: secretIv, data: fileSecret, decrypt: false) else { + return nil + } + + return EncryptedSecureIdFile(data: encryptedFileData, hash: fileHash, encryptedSecret: encryptedSecretData) +} + +func decryptedSecureIdFileSecret(context: SecureIdAccessContext, fileHash: Data, encryptedSecret: Data) -> Data? { + let secretHash = sha512Digest(context.secret + fileHash) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + guard let fileSecret = encryptSecureData(key: secretKey, iv: secretIv, data: encryptedSecret, decrypt: true) else { + return nil + } + guard verifySecureSecret(fileSecret) else { + return nil + } + return fileSecret +} + +func decryptedSecureIdFile(context: SecureIdAccessContext, encryptedData: Data, fileHash: Data, encryptedSecret: Data) -> Data? { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: fileHash, encryptedSecret: encryptedSecret) else { + return nil + } + + let fileSecretHash = sha512Digest(fileSecret + fileHash) + let fileKey = fileSecretHash.subdata(in: 0 ..< 32) + let fileIv = fileSecretHash.subdata(in: 32 ..< (32 + 16)) + guard let paddedFileData = encryptSecureData(key: fileKey, iv: fileIv, data: encryptedData, decrypt: true) else { + return nil + } + + let checkFileHash = sha256Digest(paddedFileData) + if fileHash != checkFileHash { + return nil + } + + guard let unpaddedFileData = unpaddedSecureIdData(paddedFileData) else { + return nil + } + + return unpaddedFileData +} + +public func uploadSecureIdFile(context: SecureIdAccessContext, postbox: Postbox, network: Network, resource: MediaResource) -> Signal { + return postbox.mediaBox.resourceData(resource) + |> mapError { _ -> UploadSecureIdFileError in + return .generic + } + |> mapToSignal { next -> Signal in + if !next.complete { + return .complete() + } + + guard let data = try? Data(contentsOf: URL(fileURLWithPath: next.path)) else { + return .fail(.generic) + } + + guard let encryptedData = encryptedSecureIdFile(context: context, data: data) else { + return .fail(.generic) + } + + return multipartUpload(network: network, postbox: postbox, source: .data(encryptedData.data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> mapError { _ -> UploadSecureIdFileError in + return .generic + } + |> mapToSignal { result -> Signal in + switch result { + case let .progress(value): + return .single(.progress(value)) + case let .inputFile(file): + if case let .inputFile(id, parts, _, md5Checksum) = file { + return .single(.result(UploadedSecureIdFile(id: id, parts: parts, md5Checksum: md5Checksum, fileHash: encryptedData.hash, encryptedSecret: encryptedData.encryptedSecret), encryptedData.data)) + } else { + return .fail(.generic) + } + default: + return .fail(.generic) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/VerifySecureIdValue.swift b/submodules/TelegramCore/TelegramCore/VerifySecureIdValue.swift new file mode 100644 index 0000000000..d66550476b --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/VerifySecureIdValue.swift @@ -0,0 +1,119 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif + import SwiftSignalKit +#endif + +public enum SecureIdPreparePhoneVerificationError { + case generic + case flood +} + +public struct SecureIdPreparePhoneVerificationPayload { + public let type: SentAuthorizationCodeType + public let nextType: AuthorizationCodeNextType? + public let timeout: Int32? + let phone: String + let phoneCodeHash: String +} + +public func secureIdPreparePhoneVerification(network: Network, value: SecureIdPhoneValue) -> Signal { + return network.request(Api.functions.account.sendVerifyPhoneCode(flags: 0, phoneNumber: value.phone, currentNumber: nil), automaticFloodWait: false) + |> mapError { error -> SecureIdPreparePhoneVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } + return .generic + } + |> map { sentCode -> SecureIdPreparePhoneVerificationPayload in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, timeout, _): + return SecureIdPreparePhoneVerificationPayload(type: SentAuthorizationCodeType(apiType: type), nextType: nextType.flatMap(AuthorizationCodeNextType.init), timeout: timeout, phone: value.phone, phoneCodeHash: phoneCodeHash) + } + } +} + +public enum SecureIdCommitPhoneVerificationError { + case generic + case flood + case invalid +} + +public func secureIdCommitPhoneVerification(postbox: Postbox, network: Network, context: SecureIdAccessContext, payload: SecureIdPreparePhoneVerificationPayload, code: String) -> Signal { + return network.request(Api.functions.account.verifyPhone(phoneNumber: payload.phone, phoneCodeHash: payload.phoneCodeHash, phoneCode: code)) + |> mapError { error -> SecureIdCommitPhoneVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } else if error.errorDescription == "PHONE_CODE_INVALID" { + return .invalid + } + + return .generic + } + |> mapToSignal { _ -> Signal in + return saveSecureIdValue(postbox: postbox, network: network, context: context, value: .phone(SecureIdPhoneValue(phone: payload.phone)), uploadedFiles: [:]) + |> mapError { _ -> SecureIdCommitPhoneVerificationError in + return .generic + } + } +} + +public enum SecureIdPrepareEmailVerificationError { + case generic + case invalidEmail + case flood +} + +public struct SecureIdPrepareEmailVerificationPayload { + let email: String + public let length: Int32 +} + +public func secureIdPrepareEmailVerification(network: Network, value: SecureIdEmailValue) -> Signal { + return network.request(Api.functions.account.sendVerifyEmailCode(email: value.email), automaticFloodWait: false) + |> mapError { error -> SecureIdPrepareEmailVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } else if error.errorDescription.hasPrefix("EMAIL_INVALID") { + return .invalidEmail + } + return .generic + } + |> map { sentCode -> SecureIdPrepareEmailVerificationPayload in + switch sentCode { + case .sentEmailCode(_, let length): + return SecureIdPrepareEmailVerificationPayload(email: value.email, length: length) + } + } +} + +public enum SecureIdCommitEmailVerificationError { + case generic + case flood + case invalid +} + +public func secureIdCommitEmailVerification(postbox: Postbox, network: Network, context: SecureIdAccessContext, payload: SecureIdPrepareEmailVerificationPayload, code: String) -> Signal { + return network.request(Api.functions.account.verifyEmail(email: payload.email, code: code), automaticFloodWait: false) + |> mapError { error -> SecureIdCommitEmailVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .flood + } + return .generic + } + |> mapToSignal { _ -> Signal in + return saveSecureIdValue(postbox: postbox, network: network, context: context, value: .email(SecureIdEmailValue(email: payload.email)), uploadedFiles: [:]) + |> mapError { _ -> SecureIdCommitEmailVerificationError in + return .generic + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/ViewCountMessageAttribute.swift b/submodules/TelegramCore/TelegramCore/ViewCountMessageAttribute.swift new file mode 100644 index 0000000000..fe75c429f2 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/ViewCountMessageAttribute.swift @@ -0,0 +1,24 @@ +import Foundation +#if os(macOS) + import PostboxMac +#else + import Postbox +#endif + +public class ViewCountMessageAttribute: MessageAttribute { + public let count: Int + + public var associatedMessageIds: [MessageId] = [] + + init(count: Int) { + self.count = count + } + + required public init(decoder: PostboxDecoder) { + self.count = Int(decoder.decodeInt32ForKey("c", orElse: 0)) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(Int32(self.count), forKey: "c") + } +} diff --git a/submodules/TelegramCore/TelegramCore/VoipConfiguration.swift b/submodules/TelegramCore/TelegramCore/VoipConfiguration.swift new file mode 100644 index 0000000000..089134eded --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/VoipConfiguration.swift @@ -0,0 +1,59 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public enum VoiceCallP2PMode: Int32 { + case never = 0 + case contacts = 1 + case always = 2 +} + +public struct VoipConfiguration: PreferencesEntry, Equatable { + public var serializedData: String? + + public static var defaultValue: VoipConfiguration { + return VoipConfiguration(serializedData: nil) + } + + init(serializedData: String?) { + self.serializedData = serializedData + } + + public init(decoder: PostboxDecoder) { + self.serializedData = decoder.decodeOptionalStringForKey("serializedData") + } + + public func encode(_ encoder: PostboxEncoder) { + if let serializedData = self.serializedData { + encoder.encodeString(serializedData, forKey: "serializedData") + } else { + encoder.encodeNil(forKey: "serializedData") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + guard let to = to as? VoipConfiguration else { + return false + } + return self == to + } +} + +public func currentVoipConfiguration(transaction: Transaction) -> VoipConfiguration { + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.voipConfiguration) as? VoipConfiguration { + return entry + } else { + return VoipConfiguration.defaultValue + } +} + +func updateVoipConfiguration(transaction: Transaction, _ f: (VoipConfiguration) -> VoipConfiguration) { + let current = currentVoipConfiguration(transaction: transaction) + let updated = f(current) + if updated != current { + transaction.setPreferencesEntry(key: PreferencesKeys.voipConfiguration, value: updated) + } +} diff --git a/submodules/TelegramCore/TelegramCore/Wallpaper.swift b/submodules/TelegramCore/TelegramCore/Wallpaper.swift new file mode 100644 index 0000000000..6bb2d88366 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Wallpaper.swift @@ -0,0 +1,201 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +public struct WallpaperSettings: PostboxCoding, Equatable { + public let blur: Bool + public let motion: Bool + public let color: Int32? + public let intensity: Int32? + + public init(blur: Bool = false, motion: Bool = false, color: Int32? = nil, intensity: Int32? = nil) { + self.blur = blur + self.motion = motion + self.color = color + self.intensity = intensity + } + + public init(decoder: PostboxDecoder) { + self.blur = decoder.decodeInt32ForKey("b", orElse: 0) != 0 + self.motion = decoder.decodeInt32ForKey("m", orElse: 0) != 0 + self.color = decoder.decodeOptionalInt32ForKey("c") + self.intensity = decoder.decodeOptionalInt32ForKey("i") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.blur ? 1 : 0, forKey: "b") + encoder.encodeInt32(self.motion ? 1 : 0, forKey: "m") + if let color = self.color { + encoder.encodeInt32(color, forKey: "c") + } else { + encoder.encodeNil(forKey: "c") + } + if let intensity = self.intensity { + encoder.encodeInt32(intensity, forKey: "i") + } else { + encoder.encodeNil(forKey: "i") + } + } +} + +public enum TelegramWallpaper: OrderedItemListEntryContents, Equatable { + case builtin(WallpaperSettings) + case color(Int32) + case image([TelegramMediaImageRepresentation], WallpaperSettings) + case file(id: Int64, accessHash: Int64, isCreator: Bool, isDefault: Bool, isPattern: Bool, isDark: Bool, slug: String, file: TelegramMediaFile, settings: WallpaperSettings) + + public init(decoder: PostboxDecoder) { + switch decoder.decodeInt32ForKey("v", orElse: 0) { + case 0: + let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() + self = .builtin(settings) + case 1: + self = .color(decoder.decodeInt32ForKey("c", orElse: 0)) + case 2: + let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() + self = .image(decoder.decodeObjectArrayWithDecoderForKey("i"), settings) + case 3: + let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() + if let file = decoder.decodeObjectForKey("file", decoder: { TelegramMediaFile(decoder: $0) }) as? TelegramMediaFile { + self = .file(id: decoder.decodeInt64ForKey("id", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), isCreator: decoder.decodeInt32ForKey("isCreator", orElse: 0) != 0, isDefault: decoder.decodeInt32ForKey("isDefault", orElse: 0) != 0, isPattern: decoder.decodeInt32ForKey("isPattern", orElse: 0) != 0, isDark: decoder.decodeInt32ForKey("isDark", orElse: 0) != 0, slug: decoder.decodeStringForKey("slug", orElse: ""), file: decoder.decodeObjectForKey("file", decoder: { TelegramMediaFile(decoder: $0) }) as! TelegramMediaFile, settings: settings) + } else { + self = .color(0xffffff) + } + + default: + assertionFailure() + self = .color(0xffffff) + } + } + + public var hasWallpaper: Bool { + switch self { + case .color: + return false + default: + return true + } + } + + public func encode(_ encoder: PostboxEncoder) { + switch self { + case let .builtin(settings): + encoder.encodeInt32(0, forKey: "v") + encoder.encodeObject(settings, forKey: "settings") + case let .color(color): + encoder.encodeInt32(1, forKey: "v") + encoder.encodeInt32(color, forKey: "c") + case let .image(representations, settings): + encoder.encodeInt32(2, forKey: "v") + encoder.encodeObjectArray(representations, forKey: "i") + encoder.encodeObject(settings, forKey: "settings") + case let .file(id, accessHash, isCreator, isDefault, isPattern, isDark, slug, file, settings): + encoder.encodeInt32(3, forKey: "v") + encoder.encodeInt64(id, forKey: "id") + encoder.encodeInt64(accessHash, forKey: "accessHash") + encoder.encodeInt32(isCreator ? 1 : 0, forKey: "isCreator") + encoder.encodeInt32(isDefault ? 1 : 0, forKey: "isDefault") + encoder.encodeInt32(isPattern ? 1 : 0, forKey: "isPattern") + encoder.encodeInt32(isDark ? 1 : 0, forKey: "isDark") + encoder.encodeString(slug, forKey: "slug") + encoder.encodeObject(file, forKey: "file") + encoder.encodeObject(settings, forKey: "settings") + } + } + + public static func ==(lhs: TelegramWallpaper, rhs: TelegramWallpaper) -> Bool { + switch lhs { + case let .builtin(settings): + if case .builtin(settings) = rhs { + return true + } else { + return false + } + case let .color(color): + if case .color(color) = rhs { + return true + } else { + return false + } + case let .image(representations, settings): + if case .image(representations, settings) = rhs { + return true + } else { + return false + } + case let .file(lhsId, _, lhsIsCreator, lhsIsDefault, lhsIsPattern, lhsIsDark, lhsSlug, lhsFile, lhsSettings): + if case let .file(rhsId, _, rhsIsCreator, rhsIsDefault, rhsIsPattern, rhsIsDark, rhsSlug, rhsFile, rhsSettings) = rhs, lhsId == rhsId, lhsIsCreator == rhsIsCreator, lhsIsDefault == rhsIsDefault, lhsIsPattern == rhsIsPattern, lhsIsDark == rhsIsDark, lhsSlug == rhsSlug, lhsFile == rhsFile, lhsSettings == rhsSettings { + return true + } else { + return false + } + } + } + + public var settings: WallpaperSettings? { + switch self { + case let .builtin(settings), let .image(_, settings), let .file(_, _, _, _, _, _, _, _, settings): + return settings + default: + return nil + } + } + + public func withUpdatedSettings(_ settings: WallpaperSettings) -> TelegramWallpaper { + switch self { + case .builtin: + return .builtin(settings) + case .color: + return self + case let .image(representations, _): + return .image(representations, settings) + case let .file(id, accessHash, isCreator, isDefault, isPattern, isDark, slug, file, _): + return .file(id: id, accessHash: accessHash, isCreator: isCreator, isDefault: isDefault, isPattern: isPattern, isDark: isDark, slug: slug, file: file, settings: settings) + } + } +} + +extension WallpaperSettings { + init(apiWallpaperSettings: Api.WallPaperSettings) { + switch apiWallpaperSettings { + case let .wallPaperSettings(flags, backgroundColor, intensity): + self = WallpaperSettings(blur: (flags & 1 << 1) != 0, motion: (flags & 1 << 2) != 0, color: backgroundColor, intensity: intensity) + } + } +} + +func apiWallpaperSettings(_ wallpaperSettings: WallpaperSettings) -> Api.WallPaperSettings { + var flags: Int32 = 0 + if wallpaperSettings.blur { + flags |= (1 << 1) + } + if wallpaperSettings.motion { + flags |= (1 << 2) + } + return .wallPaperSettings(flags: flags, backgroundColor: wallpaperSettings.color, intensity: wallpaperSettings.intensity) +} + +extension TelegramWallpaper { + init(apiWallpaper: Api.WallPaper) { + switch apiWallpaper { + case let .wallPaper(id, flags, accessHash, slug, document, settings): + if let file = telegramMediaFileFromApiDocument(document) { + let wallpaperSettings: WallpaperSettings + if let settings = settings { + wallpaperSettings = WallpaperSettings(apiWallpaperSettings: settings) + } else { + wallpaperSettings = WallpaperSettings() + } + self = .file(id: id, accessHash: accessHash, isCreator: (flags & 1 << 0) != 0, isDefault: (flags & 1 << 1) != 0, isPattern: (flags & 1 << 3) != 0, isDark: (flags & 1 << 4) != 0, slug: slug, file: file, settings: wallpaperSettings) + } else { + assertionFailure() + self = .color(0xffffff) + } + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Wallpapers.swift b/submodules/TelegramCore/TelegramCore/Wallpapers.swift new file mode 100644 index 0000000000..81fc0179c1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/Wallpapers.swift @@ -0,0 +1,203 @@ +import Foundation +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +#else +import Postbox +import SwiftSignalKit +#endif + +final class CachedWallpapersConfiguration: PostboxCoding { + let hash: Int32 + + init(hash: Int32) { + self.hash = hash + } + + init(decoder: PostboxDecoder) { + self.hash = decoder.decodeInt32ForKey("hash", orElse: 0) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.hash, forKey: "hash") + } +} + +public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: Bool = false) -> Signal<[TelegramWallpaper], NoError> { + let fetch: ([TelegramWallpaper]?, Int32?) -> Signal<[TelegramWallpaper], NoError> = { list, hash in + network.request(Api.functions.account.getWallPapers(hash: hash ?? 0)) + |> retryRequest + |> mapToSignal { result -> Signal<([TelegramWallpaper], Int32), NoError> in + switch result { + case let .wallPapers(hash, wallpapers): + var items: [TelegramWallpaper] = [] + var addedBuiltin = false + for apiWallpaper in wallpapers { + let wallpaper = TelegramWallpaper(apiWallpaper: apiWallpaper) + if case let .file(file) = wallpaper, !file.isDefault { + } else if !addedBuiltin { + addedBuiltin = true + items.append(.builtin(WallpaperSettings())) + } + items.append(wallpaper) + } + + if !addedBuiltin { + addedBuiltin = true + items.append(.builtin(WallpaperSettings())) + } + + if items == list { + return .complete() + } else { + return .single((items, hash)) + } + case .wallPapersNotModified: + return .complete() + } + } + |> mapToSignal { items, hash -> Signal<[TelegramWallpaper], NoError> in + return postbox.transaction { transaction -> [TelegramWallpaper] in + var entries: [OrderedItemListEntry] = [] + for item in items { + var intValue = Int32(entries.count) + let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) + entries.append(OrderedItemListEntry(id: id, contents: item)) + } + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers, items: entries) + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)), entry: CachedWallpapersConfiguration(hash: hash), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + return items + } + } + } + + if forceUpdate { + return fetch(nil, nil) + } else { + return postbox.transaction { transaction -> ([TelegramWallpaper], Int32?) in + let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0))) as? CachedWallpapersConfiguration + let items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers) + if items.count == 0 { + return ([.builtin(WallpaperSettings())], 0) + } else { + return (items.map { $0.contents as! TelegramWallpaper }, configuration?.hash) + } + } + |> mapToSignal { list, hash -> Signal<[TelegramWallpaper], NoError> in + return .single(list) + |> then(fetch(list, hash)) + } + } +} + +public enum UploadWallpaperStatus { + case progress(Float) + case complete(TelegramWallpaper) +} + +public enum UploadWallpaperError { + case generic +} + +public struct UploadedWallpaperData { + fileprivate let resource: MediaResource + fileprivate let content: UploadedWallpaperDataContent +} + +private enum UploadedWallpaperDataContent { + case result(MultipartUploadResult) + case error +} + +private func uploadedWallpaper(postbox: Postbox, network: Network, resource: MediaResource) -> Signal { + return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false) + |> map { result -> UploadedWallpaperData in + return UploadedWallpaperData(resource: resource, content: .result(result)) + } + |> `catch` { _ -> Signal in + return .single(UploadedWallpaperData(resource: resource, content: .error)) + } +} + +public func uploadWallpaper(account: Account, resource: MediaResource, mimeType: String = "image/jpeg", settings: WallpaperSettings) -> Signal { + return uploadedWallpaper(postbox: account.postbox, network: account.network, resource: resource) + |> mapError { _ -> UploadWallpaperError in return .generic } + |> mapToSignal { result -> Signal<(UploadWallpaperStatus, MediaResource?), UploadWallpaperError> in + switch result.content { + case .error: + return .fail(.generic) + case let .result(resultData): + switch resultData { + case let .progress(progress): + return .single((.progress(progress), result.resource)) + case let .inputFile(file): + return account.network.request(Api.functions.account.uploadWallPaper(file: file, mimeType: mimeType, settings: apiWallpaperSettings(settings))) + |> mapError {_ in return UploadWallpaperError.generic} + |> mapToSignal { wallpaper -> Signal<(UploadWallpaperStatus, MediaResource?), UploadWallpaperError> in + return .single((.complete(TelegramWallpaper(apiWallpaper: wallpaper)), result.resource)) + } + default: + return .fail(.generic) + } + } + } + |> map { result, _ -> UploadWallpaperStatus in + return result + } +} + +public enum GetWallpaperError { + case generic +} + +public func getWallpaper(account: Account, slug: String) -> Signal { + return account.network.request(Api.functions.account.getWallPaper(wallpaper: .inputWallPaperSlug(slug: slug))) + |> mapError { _ -> GetWallpaperError in return .generic } + |> map { wallpaper -> TelegramWallpaper in + return TelegramWallpaper(apiWallpaper: wallpaper) + } +} + +public func saveWallpaper(account: Account, wallpaper: TelegramWallpaper) -> Signal { + return saveUnsaveWallpaper(account: account, wallpaper: wallpaper, unsave: false) +} + +public func deleteWallpaper(account: Account, wallpaper: TelegramWallpaper) -> Signal { + return saveUnsaveWallpaper(account: account, wallpaper: wallpaper, unsave: true) +} + +private func saveUnsaveWallpaper(account: Account, wallpaper: TelegramWallpaper, unsave: Bool) -> Signal { + guard case let .file(_, _, _, _, _, _, slug, _, settings) = wallpaper else { + return .complete() + } + return account.network.request(Api.functions.account.saveWallPaper(wallpaper: Api.InputWallPaper.inputWallPaperSlug(slug: slug), unsave: unsave ? Api.Bool.boolTrue : Api.Bool.boolFalse, settings: apiWallpaperSettings(settings))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +public func installWallpaper(account: Account, wallpaper: TelegramWallpaper) -> Signal { + guard case let .file(_, _, _, _, _, _, slug, _, settings) = wallpaper else { + return .complete() + } + return account.network.request(Api.functions.account.installWallPaper(wallpaper: Api.InputWallPaper.inputWallPaperSlug(slug: slug), settings: apiWallpaperSettings(settings))) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +public func resetWallpapers(account: Account) -> Signal { + return account.network.request(Api.functions.account.resetWallPapers()) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/submodules/TelegramCore/TelegramCore/WebpagePreview.swift b/submodules/TelegramCore/TelegramCore/WebpagePreview.swift new file mode 100644 index 0000000000..c644609f16 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/WebpagePreview.swift @@ -0,0 +1,127 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public func webpagePreview(account: Account, url: String, webpageId: MediaId? = nil) -> Signal { + return webpagePreviewWithProgress(account: account, url: url) + |> mapToSignal { next -> Signal in + if case let .result(result) = next { + return .single(result) + } else { + return .complete() + } + } +} + +public enum WebpagePreviewWithProgressResult { + case result(TelegramMediaWebpage?) + case progress(Float) +} + +public func webpagePreviewWithProgress(account: Account, url: String, webpageId: MediaId? = nil) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let webpageId = webpageId, let webpage = transaction.getMedia(webpageId) as? TelegramMediaWebpage { + return .single(.result(webpage)) + } else { + return account.network.requestWithAdditionalInfo(Api.functions.messages.getWebPagePreview(flags: 0, message: url, entities: nil), info: .progress) + |> `catch` { _ -> Signal, NoError> in + return .single(.result(.messageMediaEmpty)) + } + |> mapToSignal { result -> Signal in + switch result { + case .acknowledged: + return .complete() + case let .progress(progress, packetSize): + if packetSize > 1024 { + return .single(.progress(progress)) + } else { + return .complete() + } + case let .result(result): + if let preCachedResources = result.preCachedResources { + for (resource, data) in preCachedResources { + account.postbox.mediaBox.storeResourceData(resource.id, data: data) + } + } + switch result { + case let .messageMediaWebPage(webpage): + if let media = telegramMediaWebpageFromApiWebpage(webpage, url: url) { + if case .Loaded = media.content { + return .single(.result(media)) + } else { + return .single(.result(media)) + |> then( + account.stateManager.updatedWebpage(media.webpageId) + |> take(1) + |> map { next -> WebpagePreviewWithProgressResult in + return .result(next) + } + ) + } + } else { + return .single(.result(nil)) + } + default: + return .single(.result(nil)) + } + } + } + } + } + |> switchToLatest +} + +public func actualizedWebpage(postbox: Postbox, network: Network, webpage: TelegramMediaWebpage) -> Signal { + if case let .Loaded(content) = webpage.content { + return network.request(Api.functions.messages.getWebPage(url: content.url, hash: content.hash)) + |> `catch` { _ -> Signal in + return .single(.webPageNotModified) + } + |> mapToSignal { result -> Signal in + if let updatedWebpage = telegramMediaWebpageFromApiWebpage(result, url: nil), case .Loaded = updatedWebpage.content, updatedWebpage.webpageId == webpage.webpageId { + return postbox.transaction { transaction -> TelegramMediaWebpage in + updateMessageMedia(transaction: transaction, id: webpage.webpageId, media: updatedWebpage) + return updatedWebpage + } + } else { + return .complete() + } + } + } else { + return .complete() + } +} + +func updatedRemoteWebpage(postbox: Postbox, network: Network, webPage: WebpageReference) -> Signal { + if case let .webPage(id, url) = webPage.content { + return network.request(Api.functions.messages.getWebPage(url: url, hash: 0)) + |> `catch` { _ -> Signal in + return .single(.webPageNotModified) + } + |> mapToSignal { result -> Signal in + if let updatedWebpage = telegramMediaWebpageFromApiWebpage(result, url: nil), case .Loaded = updatedWebpage.content, updatedWebpage.webpageId.id == id { + return postbox.transaction { transaction -> TelegramMediaWebpage? in + if transaction.getMedia(updatedWebpage.webpageId) != nil { + updateMessageMedia(transaction: transaction, id: updatedWebpage.webpageId, media: updatedWebpage) + } + return updatedWebpage + } + } else { + return .single(nil) + } + } + } else { + return .single(nil) + } +} diff --git a/submodules/TelegramCore/TelegramCore/module.private-mac.modulemap b/submodules/TelegramCore/TelegramCore/module.private-mac.modulemap new file mode 100644 index 0000000000..4d71be2a5a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/module.private-mac.modulemap @@ -0,0 +1,3 @@ +module TelegramCoreMac.TelegramCorePrivate { + export * +} diff --git a/submodules/TelegramCore/TelegramCore/module.private.modulemap b/submodules/TelegramCore/TelegramCore/module.private.modulemap new file mode 100644 index 0000000000..06df6c843a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/module.private.modulemap @@ -0,0 +1,3 @@ +module TelegramCore.TelegramCorePrivate { + export * +} diff --git a/submodules/TelegramCore/TelegramCoreMac/Info.plist b/submodules/TelegramCore/TelegramCoreMac/Info.plist new file mode 100644 index 0000000000..6c6dba7bb1 --- /dev/null +++ b/submodules/TelegramCore/TelegramCoreMac/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2016 Peter. All rights reserved. + NSPrincipalClass + + + diff --git a/submodules/TelegramCore/TelegramCoreMac/TelegramCoreMac.h b/submodules/TelegramCore/TelegramCoreMac/TelegramCoreMac.h new file mode 100644 index 0000000000..2cef829046 --- /dev/null +++ b/submodules/TelegramCore/TelegramCoreMac/TelegramCoreMac.h @@ -0,0 +1,19 @@ +// +// TelegramCoreMac.h +// TelegramCoreMac +// +// Created by Peter on 9/5/16. +// Copyright © 2016 Peter. All rights reserved. +// + +#import + +//! Project version number for TelegramCoreMac. +FOUNDATION_EXPORT double TelegramCoreMacVersionNumber; + +//! Project version string for TelegramCoreMac. +FOUNDATION_EXPORT const unsigned char TelegramCoreMacVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/submodules/TelegramCore/TelegramCoreTests/Info.plist b/submodules/TelegramCore/TelegramCoreTests/Info.plist new file mode 100644 index 0000000000..6c6c23c43a --- /dev/null +++ b/submodules/TelegramCore/TelegramCoreTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/submodules/TelegramCore/TelegramCoreTests/TelegramCoreTests.m b/submodules/TelegramCore/TelegramCoreTests/TelegramCoreTests.m new file mode 100644 index 0000000000..c0a968c85a --- /dev/null +++ b/submodules/TelegramCore/TelegramCoreTests/TelegramCoreTests.m @@ -0,0 +1,39 @@ +// +// TelegramCoreTests.m +// TelegramCoreTests +// +// Created by Peter on 8/1/16. +// Copyright © 2016 Peter. All rights reserved. +// + +#import + +@interface TelegramCoreTests : XCTestCase + +@end + +@implementation TelegramCoreTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..c35cf28d1a --- /dev/null +++ b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj @@ -0,0 +1,4105 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0900555621E4A96E0030924C /* Wallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900555521E4A96D0030924C /* Wallpaper.swift */; }; + 09028386218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */; }; + 090E778322A9862100CD99F5 /* ChannelOwnershipTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090E778222A9862100CD99F5 /* ChannelOwnershipTransfer.swift */; }; + 090E779022AAABC600CD99F5 /* PeersNearby.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090E778F22AAABC600CD99F5 /* PeersNearby.swift */; }; + 093857A82243D87900EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857A62243D87800EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift */; }; + 093857A92243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857A72243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift */; }; + 093857AB2243D88D00EB6A54 /* EmojiKeywords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857AA2243D88C00EB6A54 /* EmojiKeywords.swift */; }; + 0962E66721B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66621B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift */; }; + 0962E66921B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66821B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift */; }; + 0962E66B21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66A21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift */; }; + 0962E66D21B5C56F00245FD9 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66C21B5C56F00245FD9 /* JSON.swift */; }; + 0962E66F21B6147600245FD9 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66E21B6147600245FD9 /* AppConfiguration.swift */; }; + 0962E67521B6437600245FD9 /* SplitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67421B6437600245FD9 /* SplitTest.swift */; }; + 0962E68121BAA20E00245FD9 /* SearchBotsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */; }; + 09EDAD382213120C0012A50B /* AutodownloadSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */; }; + 09EDAD3A22131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */; }; + 9F06831021A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */; }; + 9F06831121A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */; }; + 9F10CE8B20613C78002DD61A /* SecretApiLayer73.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */; }; + 9F10CE8C20613CDB002DD61A /* TelegramDeviceContactImportInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F7732052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift */; }; + 9F153D1021E8E0A200B95D82 /* Wallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0900555521E4A96D0030924C /* Wallpaper.swift */; }; + 9F1BC1AB2244CFED00F21815 /* EmojiKeywords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857AA2243D88C00EB6A54 /* EmojiKeywords.swift */; }; + 9F1BC1AC2244CFED00F21815 /* SynchronizeEmojiKeywordsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857A72243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift */; }; + 9F1BC1AD2244CFED00F21815 /* ManagedSynchronizeEmojiKeywordsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 093857A62243D87800EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift */; }; + 9F4EEF9B21DCF66F002C3B33 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66C21B5C56F00245FD9 /* JSON.swift */; }; + 9F4EEF9C21DCF66F002C3B33 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66E21B6147600245FD9 /* AppConfiguration.swift */; }; + 9F4EEF9D21DCF66F002C3B33 /* SearchBotsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */; }; + 9F4EEF9E21DCF6E7002C3B33 /* ManagedVoipConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */; }; + 9F4EEF9F21DCF6E7002C3B33 /* ManagedAppConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66621B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift */; }; + 9F4EEFA021DCF6E7002C3B33 /* SynchronizeAppLogEventsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66821B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift */; }; + 9F4EEFA121DCF6E7002C3B33 /* ManagedSynchronizeAppLogEventsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66A21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift */; }; + 9F7D42262223FF49007B68BB /* AutodownloadSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */; }; + 9F7D42272223FF49007B68BB /* ManagedAutodownloadSettingsUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */; }; + 9FAA268820D457A300D26CF3 /* RemoteStorageConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EA188120D3D2B1001AEE19 /* RemoteStorageConfiguration.swift */; }; + 9FC8ADA9206BBD000094F7B4 /* SaveSecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D805206539D000BC3599 /* SaveSecureIdValue.swift */; }; + 9FC8ADAB206BBFF10094F7B4 /* RecentWebSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC8ADAA206BBFF10094F7B4 /* RecentWebSessions.swift */; }; + 9FC8ADAC206BC00A0094F7B4 /* RecentWebSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC8ADAA206BBFF10094F7B4 /* RecentWebSessions.swift */; }; + C205FEA81EB3B75900455808 /* ExportMessageLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C205FEA71EB3B75900455808 /* ExportMessageLink.swift */; }; + C205FEA91EB3B75900455808 /* ExportMessageLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C205FEA71EB3B75900455808 /* ExportMessageLink.swift */; }; + C210DD621FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C210DD611FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift */; }; + C210DD631FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C210DD611FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift */; }; + C22EE61B1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */; }; + C22EE61C1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */; }; + C230BEB61EE9A3760029586C /* ChannelAdminEventLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */; }; + C230BEB71EE9A3760029586C /* ChannelAdminEventLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */; }; + C2366C831E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */; }; + C2366C841E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */; }; + C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C851E4F403C0097CCFF /* AddressNames.swift */; }; + C2366C871E4F403C0097CCFF /* AddressNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C851E4F403C0097CCFF /* AddressNames.swift */; }; + C2366C891E4F40480097CCFF /* SupportPeerId.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C881E4F40480097CCFF /* SupportPeerId.swift */; }; + C2366C8A1E4F40480097CCFF /* SupportPeerId.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C881E4F40480097CCFF /* SupportPeerId.swift */; }; + C239BE971E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */; }; + C239BE981E62F0D200C2C453 /* LoadMessagesIfNecessary.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */; }; + C239BE9C1E630CA700C2C453 /* UpdatePinnedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */; }; + C239BE9D1E630CB300C2C453 /* UpdatePinnedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */; }; + C23BC3871E9BE3CA00D79F92 /* ImportContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */; }; + C23BC3881E9BE3CB00D79F92 /* ImportContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */; }; + C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C251D7421E65E50500283EDE /* StickerSetInstallation.swift */; }; + C251D7441E65E50500283EDE /* StickerSetInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C251D7421E65E50500283EDE /* StickerSetInstallation.swift */; }; + C25638021E79E7FC00311607 /* TwoStepVerification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */; }; + C26A37EF1E5E0C41006977AC /* ChannelParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BB7C591E5C8074001527C3 /* ChannelParticipants.swift */; }; + C28725421EF967E700613564 /* NotificationInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28725411EF967E700613564 /* NotificationInfoMessageAttribute.swift */; }; + C28725431EF967E700613564 /* NotificationInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28725411EF967E700613564 /* NotificationInfoMessageAttribute.swift */; }; + C28D3CF020D3DA900027F4D6 /* DeepLinkInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28D3CEF20D3DA900027F4D6 /* DeepLinkInfo.swift */; }; + C28D3CF120D3DAA30027F4D6 /* DeepLinkInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28D3CEF20D3DA900027F4D6 /* DeepLinkInfo.swift */; }; + C29340F31F5080FA0074991E /* UpdateGroupSpecificStickerset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29340F21F5080FA0074991E /* UpdateGroupSpecificStickerset.swift */; }; + C29340F41F5081280074991E /* UpdateGroupSpecificStickerset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29340F21F5080FA0074991E /* UpdateGroupSpecificStickerset.swift */; }; + C2A315C01E2E776A00D89000 /* RequestStartBot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01749581E1092BC0057C89A /* RequestStartBot.swift */; }; + C2E064681ECEEF0A00387BB8 /* TelegramMediaInvoice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E064671ECEEF0A00387BB8 /* TelegramMediaInvoice.swift */; }; + C2E064691ECEEF0B00387BB8 /* TelegramMediaInvoice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E064671ECEEF0A00387BB8 /* TelegramMediaInvoice.swift */; }; + C2E0646D1ECF171D00387BB8 /* TelegramMediaWebDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E0646C1ECF171D00387BB8 /* TelegramMediaWebDocument.swift */; }; + C2E0646E1ECF171E00387BB8 /* TelegramMediaWebDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E0646C1ECF171D00387BB8 /* TelegramMediaWebDocument.swift */; }; + C2F4ED1D1EC60064005F2696 /* RateCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F4ED1C1EC60064005F2696 /* RateCall.swift */; }; + C2F4ED1E1EC60064005F2696 /* RateCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F4ED1C1EC60064005F2696 /* RateCall.swift */; }; + C2FD33E11E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33E01E680E9E008D13D4 /* RequestUserPhotos.swift */; }; + C2FD33E21E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33E01E680E9E008D13D4 /* RequestUserPhotos.swift */; }; + C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33E31E687BF1008D13D4 /* PeerPhotoUpdater.swift */; }; + C2FD33E51E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33E31E687BF1008D13D4 /* PeerPhotoUpdater.swift */; }; + C2FD33EB1E696C78008D13D4 /* GroupsInCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33EA1E696C78008D13D4 /* GroupsInCommon.swift */; }; + C2FD33EC1E696C79008D13D4 /* GroupsInCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FD33EA1E696C78008D13D4 /* GroupsInCommon.swift */; }; + D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CFF1D62255C00955575 /* ChannelState.swift */; }; + D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; }; + D001F3EA1E128A1C007A8C60 /* TelegramPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */; }; + D001F3EB1E128A1C007A8C60 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; }; + D001F3EC1E128A1C007A8C60 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; }; + D001F3EE1E128A1C007A8C60 /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; }; + D001F3EF1E128A1C007A8C60 /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; }; + D001F3F01E128A1C007A8C60 /* AccountStateManagementUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */; }; + D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; }; + D001F3F21E128A1C007A8C60 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; }; + D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; }; + D001F3F41E128A1C007A8C60 /* UpdatesApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */; }; + D001F3F51E128A1C007A8C60 /* PendingMessageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */; }; + D001F3F61E128A1C007A8C60 /* PendingMessageUploadedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */; }; + D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */; }; + D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; }; + D00422D321677F4500719B67 /* ManagedAccountPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00422D221677F4500719B67 /* ManagedAccountPresence.swift */; }; + D00422D421677F4500719B67 /* ManagedAccountPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00422D221677F4500719B67 /* ManagedAccountPresence.swift */; }; + D00580AE21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00580AD21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift */; }; + D00580AF21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00580AD21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift */; }; + D00BDA191EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */; }; + D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */; }; + D00BDA1C1EE5952A00C64C5E /* TelegramChannelBannedRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */; }; + D00BDA1D1EE5952A00C64C5E /* TelegramChannelBannedRights.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */; }; + D00C7CCC1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */; }; + D00C7CCD1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */; }; + D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */; }; + D00C7CE11E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */; }; + D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */; }; + D00C7CEC1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */; }; + D00D34391E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */; }; + D00D343A1E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */; }; + D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */; }; + D00D343D1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */; }; + D00D343F1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */; }; + D00D34401E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */; }; + D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */; }; + D00D34431E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */; }; + D00D34451E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */; }; + D00D34461E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */; }; + D00D97C71E32901700E5C2B6 /* PeerInputActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */; }; + D00D97C81E32901700E5C2B6 /* PeerInputActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */; }; + D00D97CA1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */; }; + D00D97CB1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */; }; + D00DBBD71E64E41100DB5485 /* CreateSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00DBBD61E64E41100DB5485 /* CreateSecretChat.swift */; }; + D00DBBD81E64E41100DB5485 /* CreateSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00DBBD61E64E41100DB5485 /* CreateSecretChat.swift */; }; + D00DBBDA1E64E67E00DB5485 /* UpdateSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00DBBD91E64E67E00DB5485 /* UpdateSecretChat.swift */; }; + D00DBBDB1E64E67E00DB5485 /* UpdateSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00DBBD91E64E67E00DB5485 /* UpdateSecretChat.swift */; }; + D0119CB020CA9EA800895300 /* MarkAllChatsAsRead.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0119CAF20CA9EA800895300 /* MarkAllChatsAsRead.swift */; }; + D0119CB120CA9EA800895300 /* MarkAllChatsAsRead.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0119CAF20CA9EA800895300 /* MarkAllChatsAsRead.swift */; }; + D0136309208F3B0900EB3653 /* SecureIdValueContentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0136308208F3B0900EB3653 /* SecureIdValueContentError.swift */; }; + D013630A208F6E2800EB3653 /* SecureIdValueContentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0136308208F3B0900EB3653 /* SecureIdValueContentError.swift */; }; + D014193922AE6B85008667CB /* ChannelOwnershipTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090E778222A9862100CD99F5 /* ChannelOwnershipTransfer.swift */; }; + D014193A22AE6B85008667CB /* PeersNearby.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090E778F22AAABC600CD99F5 /* PeersNearby.swift */; }; + D015E00E225CA61100CB9E8A /* FindChannelById.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015E00D225CA61100CB9E8A /* FindChannelById.swift */; }; + D015E00F225CA61100CB9E8A /* FindChannelById.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015E00D225CA61100CB9E8A /* FindChannelById.swift */; }; + D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01749581E1092BC0057C89A /* RequestStartBot.swift */; }; + D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; }; + D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; }; + D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; }; + D01843A82190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */; }; + D01843A92190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */; }; + D018D3371E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; }; + D018D3381E648ACF00C5E089 /* ChannelCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018D3361E648ACF00C5E089 /* ChannelCreation.swift */; }; + D018EE002044939F00CBB130 /* SecretApiLayer73.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */; }; + D018EE0220458E1E00CBB130 /* SecretChatLayerNegotiation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */; }; + D018EE0320458E1E00CBB130 /* SecretChatLayerNegotiation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */; }; + D018EE052045E95000CBB130 /* CheckPeerChatServiceActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EE042045E95000CBB130 /* CheckPeerChatServiceActions.swift */; }; + D018EE062045E95000CBB130 /* CheckPeerChatServiceActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D018EE042045E95000CBB130 /* CheckPeerChatServiceActions.swift */; }; + D019B1CC1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D019B1CB1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift */; }; + D019B1CD1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D019B1CB1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift */; }; + D01A21A61F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21A51F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift */; }; + D01A21A71F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21A51F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift */; }; + D01A21A91F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21A81F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift */; }; + D01A21AA1F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21A81F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift */; }; + D01A21AC1F38D10E00DDA104 /* SavedStickerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21AB1F38D10E00DDA104 /* SavedStickerItem.swift */; }; + D01A21AD1F38D10E00DDA104 /* SavedStickerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A21AB1F38D10E00DDA104 /* SavedStickerItem.swift */; }; + D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */; }; + D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */; }; + D01AC9231DD5E9A200E8160F /* ApplyUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */; }; + D01B27A21E394D8B0022A4C0 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01B27A11E394D8B0022A4C0 /* PrivacySettings.swift */; }; + D01C06B71FBBA269001561AB /* CanSendMessagesToPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C06B61FBBA269001561AB /* CanSendMessagesToPeer.swift */; }; + D01C06B81FBBA269001561AB /* CanSendMessagesToPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C06B61FBBA269001561AB /* CanSendMessagesToPeer.swift */; }; + D01C7ED31EF5DF83008305F1 /* LimitsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7ED21EF5DF83008305F1 /* LimitsConfiguration.swift */; }; + D01C7ED41EF5DF83008305F1 /* LimitsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7ED21EF5DF83008305F1 /* LimitsConfiguration.swift */; }; + D01C7ED61EF5E468008305F1 /* ProxySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7ED51EF5E468008305F1 /* ProxySettings.swift */; }; + D01C7ED71EF5E468008305F1 /* ProxySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7ED51EF5E468008305F1 /* ProxySettings.swift */; }; + D01C7F041EFC1C49008305F1 /* DeviceContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F031EFC1C49008305F1 /* DeviceContact.swift */; }; + D01C7F051EFC1C49008305F1 /* DeviceContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F031EFC1C49008305F1 /* DeviceContact.swift */; }; + D01D6BF91E42A713006151C6 /* SearchStickers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01D6BF81E42A713006151C6 /* SearchStickers.swift */; }; + D01D6BFA1E42A718006151C6 /* SearchStickers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01D6BF81E42A713006151C6 /* SearchStickers.swift */; }; + D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0DE1DB539FC00C6B04F /* StickerPack.swift */; }; + D021E0E21DB5401A00C6B04F /* StickerManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E11DB5401A00C6B04F /* StickerManagement.swift */; }; + D0223A981EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; }; + D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; }; + D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; }; + D0223A9C1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; }; + D02395D61F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */; }; + D02395D71F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */; }; + D023E67821540624008C27D1 /* UpdateMessageMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D023E67721540624008C27D1 /* UpdateMessageMedia.swift */; }; + D023E67921540624008C27D1 /* UpdateMessageMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D023E67721540624008C27D1 /* UpdateMessageMedia.swift */; }; + D026099E20C695AF006C34AC /* Wallpapers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D026099D20C695AF006C34AC /* Wallpapers.swift */; }; + D026099F20C695AF006C34AC /* Wallpapers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D026099D20C695AF006C34AC /* Wallpapers.swift */; }; + D02609BF20C6EC08006C34AC /* Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = D02609BE20C6EC08006C34AC /* Crypto.m */; }; + D02609C020C6EC08006C34AC /* Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = D02609BE20C6EC08006C34AC /* Crypto.m */; }; + D02ABC7B1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; }; + D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; }; + D02ABC7E1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */; }; + D02ABC7F1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */; }; + D02ABC811E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */; }; + D02ABC821E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */; }; + D02B199021FB1D520094A764 /* RegisterNotificationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02B198F21FB1D520094A764 /* RegisterNotificationToken.swift */; }; + D02D60A7206BA5F900FEFE1E /* SecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60A6206BA5F900FEFE1E /* SecureIdValue.swift */; }; + D02D60A8206BA5F900FEFE1E /* SecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60A6206BA5F900FEFE1E /* SecureIdValue.swift */; }; + D02D60AB206BA64100FEFE1E /* VerifySecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60AA206BA64100FEFE1E /* VerifySecureIdValue.swift */; }; + D02D60AC206BA64100FEFE1E /* VerifySecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60AA206BA64100FEFE1E /* VerifySecureIdValue.swift */; }; + D02DADC12139A1FC00116225 /* ContactSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02DADC02139A1FC00116225 /* ContactSyncManager.swift */; }; + D02DADC22139A1FC00116225 /* ContactSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02DADC02139A1FC00116225 /* ContactSyncManager.swift */; }; + D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */; }; + D032F5BC20EF84FD00037B6C /* FetchedMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032F5BB20EF84FD00037B6C /* FetchedMediaResource.swift */; }; + D032F5BD20EF84FD00037B6C /* FetchedMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032F5BB20EF84FD00037B6C /* FetchedMediaResource.swift */; }; + D0338740223BD48B007A2CE4 /* ContactsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033873F223BD48B007A2CE4 /* ContactsSettings.swift */; }; + D0338741223BD48B007A2CE4 /* ContactsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033873F223BD48B007A2CE4 /* ContactsSettings.swift */; }; + D0338743223BD532007A2CE4 /* InitializeAccountAfterLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0338742223BD532007A2CE4 /* InitializeAccountAfterLogin.swift */; }; + D0338744223BD532007A2CE4 /* InitializeAccountAfterLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0338742223BD532007A2CE4 /* InitializeAccountAfterLogin.swift */; }; + D033FEB01E61EB0200644997 /* PeerContactSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEAF1E61EB0200644997 /* PeerContactSettings.swift */; }; + D033FEB11E61EB0200644997 /* PeerContactSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEAF1E61EB0200644997 /* PeerContactSettings.swift */; }; + D033FEB31E61F3C000644997 /* ReportPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB21E61F3C000644997 /* ReportPeer.swift */; }; + D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB21E61F3C000644997 /* ReportPeer.swift */; }; + D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; }; + D033FEB71E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; }; + D0380DBA204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0380DB9204EF306000414AB /* MessageMediaPreuploadManager.swift */; }; + D0380DBB204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0380DB9204EF306000414AB /* MessageMediaPreuploadManager.swift */; }; + D03B0CB91D62233400955575 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; }; + D03B0CBD1D62234300955575 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; }; + D03B0CBF1D62234A00955575 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; }; + D03B0CC11D62235000955575 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; }; + D03B0CCE1D62239600955575 /* PhoneNumbers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CCD1D62239600955575 /* PhoneNumbers.swift */; }; + D03B0CD31D62244300955575 /* Namespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD21D62244300955575 /* Namespaces.swift */; }; + D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD41D62245300955575 /* TelegramUser.swift */; }; + D03B0CD71D62245300955575 /* TelegramGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD51D62245300955575 /* TelegramGroup.swift */; }; + D03B0CD91D62245B00955575 /* PeerUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD81D62245B00955575 /* PeerUtils.swift */; }; + D03B0CDB1D62245F00955575 /* ApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CDA1D62245F00955575 /* ApiUtils.swift */; }; + D03B0CE01D62249100955575 /* StoreMessage_Telegram.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CDF1D62249100955575 /* StoreMessage_Telegram.swift */; }; + D03B0CE21D62249B00955575 /* InlineBotMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE11D62249B00955575 /* InlineBotMessageAttribute.swift */; }; + D03B0CE41D62249F00955575 /* TextEntitiesMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE31D62249F00955575 /* TextEntitiesMessageAttribute.swift */; }; + D03B0CE61D6224A700955575 /* ReplyMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE51D6224A700955575 /* ReplyMessageAttribute.swift */; }; + D03B0CE81D6224AD00955575 /* ViewCountMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE71D6224AD00955575 /* ViewCountMessageAttribute.swift */; }; + D03B0CF41D62250800955575 /* TelegramMediaAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEC1D62250800955575 /* TelegramMediaAction.swift */; }; + D03B0CF51D62250800955575 /* TelegramMediaContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CED1D62250800955575 /* TelegramMediaContact.swift */; }; + D03B0CF61D62250800955575 /* TelegramMediaFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEE1D62250800955575 /* TelegramMediaFile.swift */; }; + D03B0CF71D62250800955575 /* TelegramMediaImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEF1D62250800955575 /* TelegramMediaImage.swift */; }; + D03B0CF91D62250800955575 /* TelegramMediaMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CF11D62250800955575 /* TelegramMediaMap.swift */; }; + D03B0CFB1D62250800955575 /* TelegramMediaWebpage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CF31D62250800955575 /* TelegramMediaWebpage.swift */; }; + D03B0D081D62255C00955575 /* ChannelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CFF1D62255C00955575 /* ChannelState.swift */; }; + D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; }; + D03B0D0A1D62255C00955575 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; }; + D03B0D0C1D62255C00955575 /* AccountStateManagementUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */; }; + D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; }; + D03B0D0E1D62255C00955575 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; }; + D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; }; + D03B0D101D62255C00955575 /* UpdatesApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */; }; + D03B0D3D1D6319E200955575 /* Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D391D6319E200955575 /* Fetch.swift */; }; + D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D431D6319F900955575 /* CloudFileMediaResource.swift */; }; + D03B0D5B1D631A6900955575 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D551D631A6900955575 /* Buffer.swift */; }; + D03B0D5C1D631A6900955575 /* Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D561D631A6900955575 /* Download.swift */; }; + D03B0D5D1D631A6900955575 /* MultipartFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D571D631A6900955575 /* MultipartFetch.swift */; }; + D03B0D5E1D631A6900955575 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D581D631A6900955575 /* Network.swift */; }; + D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D591D631A6900955575 /* Serialization.swift */; }; + D03B0D651D631A8B00955575 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D611D631A8B00955575 /* Account.swift */; }; + D03B0D671D631A8B00955575 /* AccountViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D631D631A8B00955575 /* AccountViewTracker.swift */; }; + D03B0D681D631A8B00955575 /* RecentPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D641D631A8B00955575 /* RecentPeers.swift */; }; + D03B0D6D1D631AA300955575 /* ContactManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D6C1D631AA300955575 /* ContactManagement.swift */; }; + D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D711D631ABA00955575 /* SearchMessages.swift */; }; + D03B0E431D631E6600955575 /* NetworkLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E411D631E6600955575 /* NetworkLogging.h */; }; + D03B0E441D631E6600955575 /* NetworkLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = D03B0E421D631E6600955575 /* NetworkLogging.m */; }; + D03B0E5C1D63241D00955575 /* TelegramCoreIncludes.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E5B1D63240700955575 /* TelegramCoreIncludes.h */; }; + D03C53671DAD5CA9004C17B3 /* ApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CDA1D62245F00955575 /* ApiUtils.swift */; }; + D03C53681DAD5CA9004C17B3 /* PeerUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD81D62245B00955575 /* PeerUtils.swift */; }; + D03C53691DAD5CA9004C17B3 /* PeerAccessRestrictionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09A2FEA1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift */; }; + D03C536A1DAD5CA9004C17B3 /* TelegramUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD41D62245300955575 /* TelegramUser.swift */; }; + D03C536B1DAD5CA9004C17B3 /* TelegramGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD51D62245300955575 /* TelegramGroup.swift */; }; + D03C536C1DAD5CA9004C17B3 /* TelegramChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09A2FE51D7CD4940018FB72 /* TelegramChannel.swift */; }; + D03C536D1DAD5CA9004C17B3 /* ApiGroupOrChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B417C01D7DCEEF004562A4 /* ApiGroupOrChannel.swift */; }; + D03C536E1DAD5CA9004C17B3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; }; + D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8438B1DA7CF50005F29E1 /* BotInfo.swift */; }; + D03C53701DAD5CA9004C17B3 /* ExportedInvitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843881DA7AB96005F29E1 /* ExportedInvitation.swift */; }; + D03C53711DAD5CA9004C17B3 /* CachedGroupParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8438D1DA7D296005F29E1 /* CachedGroupParticipants.swift */; }; + D03C53721DAD5CA9004C17B3 /* CachedUserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */; }; + D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */; }; + D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */; }; + D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */; }; + D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; }; + D03DC9101F82E344001D584C /* AccountStateReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC90F1F82E344001D584C /* AccountStateReset.swift */; }; + D03DC9111F82E344001D584C /* AccountStateReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC90F1F82E344001D584C /* AccountStateReset.swift */; }; + D03DC9131F82F89D001D584C /* RegularChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC9121F82F89D001D584C /* RegularChatState.swift */; }; + D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC9121F82F89D001D584C /* RegularChatState.swift */; }; + D03E5E0C1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; }; + D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; }; + D041E3F51E535464008C24B4 /* AddPeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F41E535464008C24B4 /* AddPeerMember.swift */; }; + D041E3F61E535464008C24B4 /* AddPeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F41E535464008C24B4 /* AddPeerMember.swift */; }; + D041E3F81E535A88008C24B4 /* RemovePeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */; }; + D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */; }; + D042C6831E8D9DF800C863B0 /* Unixtime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D042C6821E8D9DF800C863B0 /* Unixtime.swift */; }; + D042C6841E8D9DF800C863B0 /* Unixtime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D042C6821E8D9DF800C863B0 /* Unixtime.swift */; }; + D0439B5D228ECB270067E026 /* RequestPhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0439B5C228ECB270067E026 /* RequestPhoneNumber.swift */; }; + D0439B5E228ECB270067E026 /* RequestPhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0439B5C228ECB270067E026 /* RequestPhoneNumber.swift */; }; + D0439B60228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0439B5F228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift */; }; + D0439B61228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0439B5F228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift */; }; + D0448C8E1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */; }; + D0448C8F1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */; }; + D0448C911E251F96005A61A7 /* SecretChatEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */; }; + D0448C921E251F96005A61A7 /* SecretChatEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */; }; + D0448C991E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C981E268F9A005A61A7 /* SecretApiLayer46.swift */; }; + D0448C9A1E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C981E268F9A005A61A7 /* SecretApiLayer46.swift */; }; + D0448C9F1E27F5EB005A61A7 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C9E1E27F5EB005A61A7 /* Random.swift */; }; + D0448CA01E27F5EB005A61A7 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C9E1E27F5EB005A61A7 /* Random.swift */; }; + D0448CA21E291B14005A61A7 /* FetchSecretFileResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448CA11E291B14005A61A7 /* FetchSecretFileResource.swift */; }; + D0448CA31E291B14005A61A7 /* FetchSecretFileResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448CA11E291B14005A61A7 /* FetchSecretFileResource.swift */; }; + D0448CA51E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */; }; + D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */; }; + D04554A621B43440007A6DD9 /* CancelAccountReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04554A521B43440007A6DD9 /* CancelAccountReset.swift */; }; + D04554A721B43440007A6DD9 /* CancelAccountReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04554A521B43440007A6DD9 /* CancelAccountReset.swift */; }; + D0458C881E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */; }; + D0458C891E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */; }; + D0467D0B20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */; }; + D0467D0C20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */; }; + D0467D1520D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */; }; + D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */; }; + D048B4AC20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */; }; + D048B4AD20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */; }; + D049EAD51E43D98500A2CD3A /* RecentMediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */; }; + D049EAD61E43D98500A2CD3A /* RecentMediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */; }; + D049EAD81E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */; }; + D049EAD91E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */; }; + D049EAE81E44B67100A2CD3A /* RecentPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAE71E44B67100A2CD3A /* RecentPeerItem.swift */; }; + D049EAE91E44B67100A2CD3A /* RecentPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAE71E44B67100A2CD3A /* RecentPeerItem.swift */; }; + D049EAEB1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAEA1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift */; }; + D049EAEC1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAEA1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift */; }; + D049EAF51E44DF3300A2CD3A /* AccountState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAF41E44DF3300A2CD3A /* AccountState.swift */; }; + D049EAF61E44DF3300A2CD3A /* AccountState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAF41E44DF3300A2CD3A /* AccountState.swift */; }; + D04CAA5A1E83310D0047E51F /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04CAA591E83310D0047E51F /* MD5.swift */; }; + D04CAA5B1E83310D0047E51F /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04CAA591E83310D0047E51F /* MD5.swift */; }; + D04D8FF4209A4B0700865719 /* NetworkSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04D8FF3209A4B0700865719 /* NetworkSettings.swift */; }; + D04D8FF5209A4B0700865719 /* NetworkSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04D8FF3209A4B0700865719 /* NetworkSettings.swift */; }; + D050F2101E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D050F20F1E48AB0600988324 /* InteractivePhoneFormatter.swift */; }; + D050F2111E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D050F20F1E48AB0600988324 /* InteractivePhoneFormatter.swift */; }; + D050F2511E4A59C200988324 /* JoinLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D050F2501E4A59C200988324 /* JoinLink.swift */; }; + D050F2521E4A59C200988324 /* JoinLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D050F2501E4A59C200988324 /* JoinLink.swift */; }; + D050F2531E4A5AC500988324 /* NBAsYouTypeFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843991DA7FF30005F29E1 /* NBAsYouTypeFormatter.h */; }; + D050F2541E4A5AC500988324 /* NBMetadataCore.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439A1DA7FF30005F29E1 /* NBMetadataCore.h */; }; + D050F2551E4A5AC500988324 /* NBMetadataCoreMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439C1DA7FF30005F29E1 /* NBMetadataCoreMapper.h */; }; + D050F2561E4A5AC500988324 /* NBMetadataCoreTest.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439E1DA7FF30005F29E1 /* NBMetadataCoreTest.h */; }; + D050F2571E4A5AC500988324 /* NBMetadataCoreTestMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A01DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h */; }; + D050F2581E4A5AC500988324 /* NBMetadataHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A21DA7FF30005F29E1 /* NBMetadataHelper.h */; }; + D050F2591E4A5AC500988324 /* NBNumberFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A41DA7FF30005F29E1 /* NBNumberFormat.h */; }; + D050F25A1E4A5AC500988324 /* NBPhoneMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A61DA7FF30005F29E1 /* NBPhoneMetaData.h */; }; + D050F25B1E4A5AC500988324 /* NBPhoneMetaDataGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A81DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h */; }; + D050F25C1E4A5AC500988324 /* NBPhoneNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AA1DA7FF30005F29E1 /* NBPhoneNumber.h */; }; + D050F25D1E4A5AC500988324 /* NBPhoneNumberDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AC1DA7FF30005F29E1 /* NBPhoneNumberDefines.h */; }; + D050F25E1E4A5AC500988324 /* NBPhoneNumberDesc.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AE1DA7FF30005F29E1 /* NBPhoneNumberDesc.h */; }; + D050F25F1E4A5AC500988324 /* NBPhoneNumberUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843B01DA7FF30005F29E1 /* NBPhoneNumberUtil.h */; }; + D050F2601E4A5AD500988324 /* AutoremoveTimeoutMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1A71E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift */; }; + D050F2611E4A5AE700988324 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01B27A11E394D8B0022A4C0 /* PrivacySettings.swift */; }; + D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */; }; + D050F2631E4A5AEB00988324 /* SynchronizePinnedChatsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38781E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift */; }; + D050F2641E4A5AEB00988324 /* ManagedSynchronizePinnedChatsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38761E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift */; }; + D050F26A1E4A5B6D00988324 /* ManagedGlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */; }; + D050F26B1E4A5B6D00988324 /* ApplyMaxReadIndexInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1A91E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift */; }; + D050F26C1E4A5B6D00988324 /* UpdatePeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC386F1E40853E0044D6FE /* UpdatePeers.swift */; }; + D050F26D1E4A5B6D00988324 /* CreateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC386D1E3FDAB70044D6FE /* CreateGroup.swift */; }; + D050F26E1E4A5B6D00988324 /* RemovePeerChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38741E40A7F70044D6FE /* RemovePeerChat.swift */; }; + D051DB14215EC5A300F30F92 /* AppChangelogState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D051DB13215EC5A300F30F92 /* AppChangelogState.swift */; }; + D051DB15215EC5A300F30F92 /* AppChangelogState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D051DB13215EC5A300F30F92 /* AppChangelogState.swift */; }; + D051DB17215ECC4D00F30F92 /* AppChangelog.swift in Sources */ = {isa = PBXBuildFile; fileRef = D051DB16215ECC4D00F30F92 /* AppChangelog.swift */; }; + D051DB18215ECC4D00F30F92 /* AppChangelog.swift in Sources */ = {isa = PBXBuildFile; fileRef = D051DB16215ECC4D00F30F92 /* AppChangelog.swift */; }; + D0528E5A1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E591E658B3600E2FEF5 /* ManagedLocalInputActivities.swift */; }; + D0528E5B1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E591E658B3600E2FEF5 /* ManagedLocalInputActivities.swift */; }; + D0528E601E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */; }; + D0528E611E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */; }; + D0528E651E65C82400E2FEF5 /* UpdateContactName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */; }; + D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */; }; + D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; }; + D0528E6B1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */; }; + D0529D2421A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */; }; + D0529D2521A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */; }; + D0529D2721A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */; }; + D0529D2821A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */; }; + D053B3FB1F1651FA00E2D58A /* MonotonicTime.h in Headers */ = {isa = PBXBuildFile; fileRef = D053B3F91F1651FA00E2D58A /* MonotonicTime.h */; }; + D053B3FC1F1651FA00E2D58A /* MonotonicTime.m in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */; }; + D053B3FE1F16534400E2D58A /* MonotonicTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FD1F16534400E2D58A /* MonotonicTime.swift */; }; + D053B4181F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B4171F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift */; }; + D053B4191F18DE5000E2D58A /* AuthorSignatureMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B4171F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift */; }; + D053B41B1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B41A1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift */; }; + D053B41C1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B41A1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift */; }; + D05452071E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05452061E7B5093006EEF19 /* LoadedStickerPack.swift */; }; + D05452081E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05452061E7B5093006EEF19 /* LoadedStickerPack.swift */; }; + D054648B2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054648A2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift */; }; + D054648C2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054648A2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift */; }; + D054648E20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054648D20738626002ECC1E /* SecureIdDriversLicenseValue.swift */; }; + D054648F20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054648D20738626002ECC1E /* SecureIdDriversLicenseValue.swift */; }; + D054649120738653002ECC1E /* SecureIdIDCardValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054649020738653002ECC1E /* SecureIdIDCardValue.swift */; }; + D054649220738653002ECC1E /* SecureIdIDCardValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054649020738653002ECC1E /* SecureIdIDCardValue.swift */; }; + D0546494207386D7002ECC1E /* SecureIdUtilityBillValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0546493207386D7002ECC1E /* SecureIdUtilityBillValue.swift */; }; + D0546495207386D7002ECC1E /* SecureIdUtilityBillValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0546493207386D7002ECC1E /* SecureIdUtilityBillValue.swift */; }; + D05464972073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05464962073872C002ECC1E /* SecureIdBankStatementValue.swift */; }; + D05464982073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05464962073872C002ECC1E /* SecureIdBankStatementValue.swift */; }; + D054649A20738760002ECC1E /* SecureIdRentalAgreementValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054649920738760002ECC1E /* SecureIdRentalAgreementValue.swift */; }; + D054649B20738760002ECC1E /* SecureIdRentalAgreementValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054649920738760002ECC1E /* SecureIdRentalAgreementValue.swift */; }; + D0561DE31E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0561DE21E5737FC00E6B9E9 /* UpdatePeerInfo.swift */; }; + D0561DE41E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0561DE21E5737FC00E6B9E9 /* UpdatePeerInfo.swift */; }; + D0561DEA1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0561DE91E5754FA00E6B9E9 /* ChannelAdmins.swift */; }; + D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0561DE91E5754FA00E6B9E9 /* ChannelAdmins.swift */; }; + D0575AF11E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0575AF01E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift */; }; + D0575AF21E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0575AF01E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift */; }; + D0575AF41E9FFDDE006F2541 /* ManagedSynchronizeSavedGifsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0575AF31E9FFDDD006F2541 /* ManagedSynchronizeSavedGifsOperations.swift */; }; + D0575AF51E9FFDDE006F2541 /* ManagedSynchronizeSavedGifsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0575AF31E9FFDDD006F2541 /* ManagedSynchronizeSavedGifsOperations.swift */; }; + D058E0D11E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D058E0D01E8AD65C00A442DE /* StandaloneSendMessage.swift */; }; + D058E0D21E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D058E0D01E8AD65C00A442DE /* StandaloneSendMessage.swift */; }; + D05A32E11E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */; }; + D05A32E21E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */; }; + D05A32E41E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */; }; + D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */; }; + D05A32E71E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; }; + D05A32E81E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; }; + D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; }; + D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; }; + D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; + D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; + D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FCE1E60520700202CDB /* ChannelMembers.swift */; }; + D0613FD01E60520700202CDB /* ChannelMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FCE1E60520700202CDB /* ChannelMembers.swift */; }; + D0613FD71E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */; }; + D0613FD81E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */; }; + D0633CD22253A528003DD95F /* ChatOnlineMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0633CD12253A528003DD95F /* ChatOnlineMembers.swift */; }; + D0633CD32253A528003DD95F /* ChatOnlineMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0633CD12253A528003DD95F /* ChatOnlineMembers.swift */; }; + D0633CDB2253C0D3003DD95F /* CloudMediaResourceParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0633CDA2253C0D3003DD95F /* CloudMediaResourceParameters.swift */; }; + D0633CDC2253C0D3003DD95F /* CloudMediaResourceParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0633CDA2253C0D3003DD95F /* CloudMediaResourceParameters.swift */; }; + D0642EF91F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EF81F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift */; }; + D0642EFA1F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EF81F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift */; }; + D067066C1D512ADB00DED3E3 /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706671D512ADB00DED3E3 /* Postbox.framework */; }; + D067066D1D512ADB00DED3E3 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706681D512ADB00DED3E3 /* SwiftSignalKit.framework */; }; + D06AFE8920BF66BF00EA5124 /* DeserializeFunctionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06AFE8820BF66BF00EA5124 /* DeserializeFunctionResponse.swift */; }; + D06AFE8A20BF66BF00EA5124 /* DeserializeFunctionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06AFE8820BF66BF00EA5124 /* DeserializeFunctionResponse.swift */; }; + D06CA13522772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */; }; + D06CA13622772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */; }; + D06ECFC820B810D300C576C2 /* TermsOfService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06ECFC720B810D300C576C2 /* TermsOfService.swift */; }; + D06ECFC920B810D300C576C2 /* TermsOfService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06ECFC720B810D300C576C2 /* TermsOfService.swift */; }; + D07047B41F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B31F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift */; }; + D07047B51F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B31F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift */; }; + D07047B71F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B61F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift */; }; + D07047B81F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B61F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift */; }; + D07047BA1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B91F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift */; }; + D07047BB1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07047B91F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift */; }; + D073CE5D1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */; }; + D073CE601DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */; }; + D073CE6A1DCBCF17007511FD /* ViewCountMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE71D6224AD00955575 /* ViewCountMessageAttribute.swift */; }; + D073CE6B1DCBCF17007511FD /* ReplyMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE51D6224A700955575 /* ReplyMessageAttribute.swift */; }; + D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE31D62249F00955575 /* TextEntitiesMessageAttribute.swift */; }; + D073CE6D1DCBCF17007511FD /* InlineBotMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CE11D62249B00955575 /* InlineBotMessageAttribute.swift */; }; + D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */; }; + D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */; }; + D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0DE1DB539FC00C6B04F /* StickerPack.swift */; }; + D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; }; + D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E11DB5401A00C6B04F /* StickerManagement.swift */; }; + D0754D2A1EEE10FC00884F6E /* BotPaymentForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0754D291EEE10FC00884F6E /* BotPaymentForm.swift */; }; + D0754D2B1EEE10FC00884F6E /* BotPaymentForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0754D291EEE10FC00884F6E /* BotPaymentForm.swift */; }; + D076F8892296D8E9004F895A /* ManageChannelDiscussionGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D076F8882296D8E9004F895A /* ManageChannelDiscussionGroup.swift */; }; + D076F88A2296D8F6004F895A /* ManageChannelDiscussionGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D076F8882296D8E9004F895A /* ManageChannelDiscussionGroup.swift */; }; + D07827BB1E00451F00071108 /* SearchPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827BA1E00451F00071108 /* SearchPeers.swift */; }; + D07827C91E02F59C00071108 /* InstantPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827C81E02F59C00071108 /* InstantPage.swift */; }; + D07827CB1E02F5B200071108 /* RichText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827CA1E02F5B200071108 /* RichText.swift */; }; + D07E413F208A769D00FCA8F0 /* ProxyServersStatuses.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E413E208A769D00FCA8F0 /* ProxyServersStatuses.swift */; }; + D07E4140208A769D00FCA8F0 /* ProxyServersStatuses.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E413E208A769D00FCA8F0 /* ProxyServersStatuses.swift */; }; + D081E10A217F5ADE003CD921 /* LocalizationPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D081E109217F5ADE003CD921 /* LocalizationPreview.swift */; }; + D081E10B217F5ADE003CD921 /* LocalizationPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D081E109217F5ADE003CD921 /* LocalizationPreview.swift */; }; + D08774FC1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */; }; + D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */; }; + D08984F22114B97400918162 /* ClearCloudDrafts.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F12114B97400918162 /* ClearCloudDrafts.swift */; }; + D08984F32114B97400918162 /* ClearCloudDrafts.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F12114B97400918162 /* ClearCloudDrafts.swift */; }; + D08984F521187ECA00918162 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F421187ECA00918162 /* NetworkType.swift */; }; + D08984F621187ECA00918162 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F421187ECA00918162 /* NetworkType.swift */; }; + D08984F92118816A00918162 /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = D08984F72118816900918162 /* Reachability.h */; }; + D08984FA2118816A00918162 /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = D08984F72118816900918162 /* Reachability.h */; }; + D08984FB2118816A00918162 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = D08984F82118816A00918162 /* Reachability.m */; }; + D08984FC2118816A00918162 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = D08984F82118816A00918162 /* Reachability.m */; }; + D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; }; + D08CAA7E1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; }; + D08CAA801ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */; }; + D08CAA811ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */; }; + D08CAA841ED8164B0000FDA8 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA831ED8164B0000FDA8 /* Localization.swift */; }; + D08CAA851ED8164B0000FDA8 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA831ED8164B0000FDA8 /* Localization.swift */; }; + D08CAA871ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */; }; + D08CAA881ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */; }; + D08CAA8C1ED81EDF0000FDA8 /* Localizations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */; }; + D08CAA8D1ED81EDF0000FDA8 /* Localizations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */; }; + D08F4A661E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; + D08F4A671E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; + D08F4A691E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; + D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; + D093D7EE206413F600BC3599 /* SecureIdDataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */; }; + D093D7EF206413F600BC3599 /* SecureIdDataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */; }; + D093D7F520641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */; }; + D093D7F620641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */; }; + D093D7F920641AA500BC3599 /* SecureIdEmailValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */; }; + D093D7FA20641AA500BC3599 /* SecureIdEmailValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */; }; + D093D806206539D000BC3599 /* SaveSecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D805206539D000BC3599 /* SaveSecureIdValue.swift */; }; + D098907F22942E3B0053F151 /* ActiveSessionsContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D098907E22942E3B0053F151 /* ActiveSessionsContext.swift */; }; + D098908022942E3B0053F151 /* ActiveSessionsContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D098907E22942E3B0053F151 /* ActiveSessionsContext.swift */; }; + D099D7461EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */; }; + D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */; }; + D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */; }; + D099D74A1EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */; }; + D099E222229420D600561B75 /* BlockedPeersContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099E221229420D600561B75 /* BlockedPeersContext.swift */; }; + D099E223229420D600561B75 /* BlockedPeersContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099E221229420D600561B75 /* BlockedPeersContext.swift */; }; + D099EA1C1DE72867001AF5A8 /* PeerCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */; }; + D09A2FE61D7CD4940018FB72 /* TelegramChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09A2FE51D7CD4940018FB72 /* TelegramChannel.swift */; }; + D09A2FEB1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09A2FEA1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift */; }; + D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */; }; + D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */; }; + D09D8C0B1D4FAB1D0081DBEC /* TelegramCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D09D8C011D4FAB1D0081DBEC /* TelegramCore.framework */; }; + D09D8C101D4FAB1D0081DBEC /* TelegramCoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D09D8C0F1D4FAB1D0081DBEC /* TelegramCoreTests.m */; }; + D09D8C121D4FAB1D0081DBEC /* TelegramCore.h in Headers */ = {isa = PBXBuildFile; fileRef = D09D8C041D4FAB1D0081DBEC /* TelegramCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D09F9DC820767D2C00DB4DE1 /* Api3.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC520767D2C00DB4DE1 /* Api3.swift */; }; + D09F9DC920767D2C00DB4DE1 /* Api3.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC520767D2C00DB4DE1 /* Api3.swift */; }; + D09F9DCA20767D2C00DB4DE1 /* Api1.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC620767D2C00DB4DE1 /* Api1.swift */; }; + D09F9DCB20767D2C00DB4DE1 /* Api1.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC620767D2C00DB4DE1 /* Api1.swift */; }; + D09F9DCC20767D2C00DB4DE1 /* Api2.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC720767D2C00DB4DE1 /* Api2.swift */; }; + D09F9DCD20767D2C00DB4DE1 /* Api2.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09F9DC720767D2C00DB4DE1 /* Api2.swift */; }; + D0A3E447214802C7008ACEF6 /* VoipConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A3E446214802C7008ACEF6 /* VoipConfiguration.swift */; }; + D0A3E448214802C7008ACEF6 /* VoipConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A3E446214802C7008ACEF6 /* VoipConfiguration.swift */; }; + D0A472B61F4CBE8B00E0EEDA /* LoadedPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */; }; + D0A472B71F4CBE8B00E0EEDA /* LoadedPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */; }; + D0A8998F217A37A000759EE6 /* NotificationAutolockReportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */; }; + D0A89990217A37A000759EE6 /* NotificationAutolockReportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */; }; + D0AAD1A81E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1A71E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift */; }; + D0AAD1AA1E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1A91E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift */; }; + D0AAD1B81E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1B71E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift */; }; + D0AAD1B91E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AAD1B71E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift */; }; + D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B911D65E9FA002C78E7 /* ManagedServiceViews.swift */; }; + D0AB0B941D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B931D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift */; }; + D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B951D662F0B002C78E7 /* ManagedChatListHoles.swift */; }; + D0AB0B9A1D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B991D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift */; }; + D0AB262621C2F991008F6685 /* TelegramMediaPoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB262521C2F991008F6685 /* TelegramMediaPoll.swift */; }; + D0AB262721C2F991008F6685 /* TelegramMediaPoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB262521C2F991008F6685 /* TelegramMediaPoll.swift */; }; + D0AB262B21C3CE80008F6685 /* Polls.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB262A21C3CE80008F6685 /* Polls.swift */; }; + D0AB262C21C3CE80008F6685 /* Polls.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB262A21C3CE80008F6685 /* Polls.swift */; }; + D0AD02E31FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AD02E21FFFA14800C1DCFF /* PeerLiveLocationsContext.swift */; }; + D0AD02E41FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AD02E21FFFA14800C1DCFF /* PeerLiveLocationsContext.swift */; }; + D0ADF911212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ADF910212B00DD00310BBC /* SecureIdConfiguration.swift */; }; + D0ADF912212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ADF910212B00DD00310BBC /* SecureIdConfiguration.swift */; }; + D0AF32221FAC95C20097362B /* StandaloneUploadedMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32211FAC95C20097362B /* StandaloneUploadedMedia.swift */; }; + D0AF32231FAC95C20097362B /* StandaloneUploadedMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32211FAC95C20097362B /* StandaloneUploadedMedia.swift */; }; + D0AF32311FACEDEC0097362B /* CoreSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32301FACEDEC0097362B /* CoreSettings.swift */; }; + D0AF32321FACEDEC0097362B /* CoreSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32301FACEDEC0097362B /* CoreSettings.swift */; }; + D0AF32351FAE8C6B0097362B /* MultipeerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AF32341FAE8C6B0097362B /* MultipeerManager.swift */; }; + D0AF32381FAE8C920097362B /* MultipeerConnectivity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0AF32371FAE8C910097362B /* MultipeerConnectivity.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + D0B1671D1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */; }; + D0B1671E1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */; }; + D0B167231F9F972E00976B40 /* LoggingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B167221F9F972E00976B40 /* LoggingSettings.swift */; }; + D0B167241F9F972E00976B40 /* LoggingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B167221F9F972E00976B40 /* LoggingSettings.swift */; }; + D0B2F7742052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F7732052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift */; }; + D0B417C11D7DCEEF004562A4 /* ApiGroupOrChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B417C01D7DCEEF004562A4 /* ApiGroupOrChannel.swift */; }; + D0B4186B1D7E03D5004562A4 /* TelegramCoreMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B418691D7E03D5004562A4 /* TelegramCoreMac.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0B418721D7E0409004562A4 /* PostboxMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B418701D7E0409004562A4 /* PostboxMac.framework */; }; + D0B418731D7E0409004562A4 /* SwiftSignalKitMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B418711D7E0409004562A4 /* SwiftSignalKitMac.framework */; }; + D0B4187F1D7E054E004562A4 /* MtProtoKitMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B4187E1D7E054E004562A4 /* MtProtoKitMac.framework */; }; + D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CD21D62244300955575 /* Namespaces.swift */; }; + D0B4188E1D7E0578004562A4 /* StoreMessage_Telegram.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CDF1D62249100955575 /* StoreMessage_Telegram.swift */; }; + D0B418941D7E0580004562A4 /* TelegramMediaAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEC1D62250800955575 /* TelegramMediaAction.swift */; }; + D0B418951D7E0580004562A4 /* TelegramMediaContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CED1D62250800955575 /* TelegramMediaContact.swift */; }; + D0B418961D7E0580004562A4 /* TelegramMediaFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEE1D62250800955575 /* TelegramMediaFile.swift */; }; + D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CEF1D62250800955575 /* TelegramMediaImage.swift */; }; + D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CF11D62250800955575 /* TelegramMediaMap.swift */; }; + D0B4189B1D7E0580004562A4 /* TelegramMediaWebpage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CF31D62250800955575 /* TelegramMediaWebpage.swift */; }; + D0B418A61D7E0592004562A4 /* CloudFileMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D431D6319F900955575 /* CloudFileMediaResource.swift */; }; + D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D391D6319E200955575 /* Fetch.swift */; }; + D0B418A91D7E0597004562A4 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D551D631A6900955575 /* Buffer.swift */; }; + D0B418AA1D7E0597004562A4 /* Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D561D631A6900955575 /* Download.swift */; }; + D0B418AB1D7E0597004562A4 /* MultipartFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D571D631A6900955575 /* MultipartFetch.swift */; }; + D0B418AC1D7E0597004562A4 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D581D631A6900955575 /* Network.swift */; }; + D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D591D631A6900955575 /* Serialization.swift */; }; + D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D6C1D631AA300955575 /* ContactManagement.swift */; }; + D0B418BA1D7E05BB004562A4 /* NetworkLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = D03B0E421D631E6600955575 /* NetworkLogging.m */; }; + D0B418BB1D7E05BE004562A4 /* NetworkLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E411D631E6600955575 /* NetworkLogging.h */; }; + D0B418BC1D7E05D0004562A4 /* TelegramCoreIncludes.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E5B1D63240700955575 /* TelegramCoreIncludes.h */; }; + D0B843811DA6EDAE005F29E1 /* CachedUserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */; }; + D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */; }; + D0B843851DA6EDC4005F29E1 /* CachedChannelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */; }; + D0B843871DA6F705005F29E1 /* UpdateCachedPeerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843861DA6F705005F29E1 /* UpdateCachedPeerData.swift */; }; + D0B843891DA7AB96005F29E1 /* ExportedInvitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843881DA7AB96005F29E1 /* ExportedInvitation.swift */; }; + D0B8438C1DA7CF50005F29E1 /* BotInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8438B1DA7CF50005F29E1 /* BotInfo.swift */; }; + D0B8438E1DA7D296005F29E1 /* CachedGroupParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8438D1DA7D296005F29E1 /* CachedGroupParticipants.swift */; }; + D0B843971DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843961DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift */; }; + D0B843B21DA7FF30005F29E1 /* NBAsYouTypeFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843981DA7FF30005F29E1 /* NBAsYouTypeFormatter.m */; }; + D0B843B31DA7FF30005F29E1 /* NBAsYouTypeFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843991DA7FF30005F29E1 /* NBAsYouTypeFormatter.h */; }; + D0B843B41DA7FF30005F29E1 /* NBMetadataCore.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439A1DA7FF30005F29E1 /* NBMetadataCore.h */; }; + D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439B1DA7FF30005F29E1 /* NBMetadataCore.m */; }; + D0B843B61DA7FF30005F29E1 /* NBMetadataCoreMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439C1DA7FF30005F29E1 /* NBMetadataCoreMapper.h */; }; + D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439D1DA7FF30005F29E1 /* NBMetadataCoreMapper.m */; }; + D0B843B81DA7FF30005F29E1 /* NBMetadataCoreTest.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B8439E1DA7FF30005F29E1 /* NBMetadataCoreTest.h */; }; + D0B843B91DA7FF30005F29E1 /* NBMetadataCoreTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439F1DA7FF30005F29E1 /* NBMetadataCoreTest.m */; }; + D0B843BA1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A01DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h */; }; + D0B843BB1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A11DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m */; }; + D0B843BC1DA7FF30005F29E1 /* NBMetadataHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A21DA7FF30005F29E1 /* NBMetadataHelper.h */; }; + D0B843BD1DA7FF30005F29E1 /* NBMetadataHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A31DA7FF30005F29E1 /* NBMetadataHelper.m */; }; + D0B843BE1DA7FF30005F29E1 /* NBNumberFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A41DA7FF30005F29E1 /* NBNumberFormat.h */; }; + D0B843BF1DA7FF30005F29E1 /* NBNumberFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A51DA7FF30005F29E1 /* NBNumberFormat.m */; }; + D0B843C01DA7FF30005F29E1 /* NBPhoneMetaData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A61DA7FF30005F29E1 /* NBPhoneMetaData.h */; }; + D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A71DA7FF30005F29E1 /* NBPhoneMetaData.m */; }; + D0B843C21DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843A81DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h */; }; + D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A91DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m */; }; + D0B843C41DA7FF30005F29E1 /* NBPhoneNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AA1DA7FF30005F29E1 /* NBPhoneNumber.h */; }; + D0B843C51DA7FF30005F29E1 /* NBPhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AB1DA7FF30005F29E1 /* NBPhoneNumber.m */; }; + D0B843C61DA7FF30005F29E1 /* NBPhoneNumberDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AC1DA7FF30005F29E1 /* NBPhoneNumberDefines.h */; }; + D0B843C71DA7FF30005F29E1 /* NBPhoneNumberDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */; }; + D0B843C81DA7FF30005F29E1 /* NBPhoneNumberDesc.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843AE1DA7FF30005F29E1 /* NBPhoneNumberDesc.h */; }; + D0B843C91DA7FF30005F29E1 /* NBPhoneNumberDesc.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */; }; + D0B843CA1DA7FF30005F29E1 /* NBPhoneNumberUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B843B01DA7FF30005F29E1 /* NBPhoneNumberUtil.h */; }; + D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */; }; + D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */; }; + D0B8440E1DAB91CD005F29E1 /* MessageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */; }; + D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; }; + D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; }; + D0B844121DAB91CD005F29E1 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; }; + D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; }; + D0B844141DAB91CD005F29E1 /* PhoneNumbers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CCD1D62239600955575 /* PhoneNumbers.swift */; }; + D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843981DA7FF30005F29E1 /* NBAsYouTypeFormatter.m */; }; + D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439B1DA7FF30005F29E1 /* NBMetadataCore.m */; }; + D0B8442C1DAB91E0005F29E1 /* NBMetadataCoreMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439D1DA7FF30005F29E1 /* NBMetadataCoreMapper.m */; }; + D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B8439F1DA7FF30005F29E1 /* NBMetadataCoreTest.m */; }; + D0B8442E1DAB91E0005F29E1 /* NBMetadataCoreTestMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A11DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m */; }; + D0B8442F1DAB91E0005F29E1 /* NBMetadataHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A31DA7FF30005F29E1 /* NBMetadataHelper.m */; }; + D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A51DA7FF30005F29E1 /* NBNumberFormat.m */; }; + D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A71DA7FF30005F29E1 /* NBPhoneMetaData.m */; }; + D0B844321DAB91E0005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843A91DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m */; }; + D0B844331DAB91E0005F29E1 /* NBPhoneNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AB1DA7FF30005F29E1 /* NBPhoneNumber.m */; }; + D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */; }; + D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */; }; + D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */; }; + D0B844431DAB91FD005F29E1 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D611D631A8B00955575 /* Account.swift */; }; + D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D631D631A8B00955575 /* AccountViewTracker.swift */; }; + D0B844461DAB91FD005F29E1 /* RecentPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D641D631A8B00955575 /* RecentPeers.swift */; }; + D0B844471DAB91FD005F29E1 /* ManagedServiceViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B911D65E9FA002C78E7 /* ManagedServiceViews.swift */; }; + D0B844481DAB91FD005F29E1 /* ManagedMessageHistoryHoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B931D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift */; }; + D0B844491DAB91FD005F29E1 /* ManagedChatListHoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B951D662F0B002C78E7 /* ManagedChatListHoles.swift */; }; + D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B991D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift */; }; + D0B8444C1DAB91FD005F29E1 /* UpdateCachedPeerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843861DA6F705005F29E1 /* UpdateCachedPeerData.swift */; }; + D0B844531DAC0773005F29E1 /* TelegramUserPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */; }; + D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B85AC41F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift */; }; + D0B85AC61F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B85AC41F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift */; }; + D0BB7C5A1E5C8074001527C3 /* ChannelParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BB7C591E5C8074001527C3 /* ChannelParticipants.swift */; }; + D0BC386E1E3FDAB70044D6FE /* CreateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC386D1E3FDAB70044D6FE /* CreateGroup.swift */; }; + D0BC38701E40853E0044D6FE /* UpdatePeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC386F1E40853E0044D6FE /* UpdatePeers.swift */; }; + D0BC38751E40A7F70044D6FE /* RemovePeerChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38741E40A7F70044D6FE /* RemovePeerChat.swift */; }; + D0BC38771E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38761E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift */; }; + D0BC38791E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38781E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift */; }; + D0BC387B1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC387A1E40D2880044D6FE /* TogglePeerChatPinned.swift */; }; + D0BC387C1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC387A1E40D2880044D6FE /* TogglePeerChatPinned.swift */; }; + D0BE303A20619EE800FBE6D8 /* SecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */; }; + D0BE303B20619EE800FBE6D8 /* SecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */; }; + D0BE303D2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */; }; + D0BE303E2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */; }; + D0BE304B20627D9800FBE6D8 /* AccessSecureId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */; }; + D0BE304C20627D9800FBE6D8 /* AccessSecureId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */; }; + D0BEAF5D1E54941B00BD963D /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF5C1E54941B00BD963D /* Authorization.swift */; }; + D0BEAF5E1E54941B00BD963D /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF5C1E54941B00BD963D /* Authorization.swift */; }; + D0BEAF601E54ACF900BD963D /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */; }; + D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */; }; + D0C0B58A1ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5891ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift */; }; + D0C0B58B1ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5891ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift */; }; + D0C0B58D1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B58C1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift */; }; + D0C0B58E1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B58C1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift */; }; + D0C26D661FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D651FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift */; }; + D0C26D671FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D651FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift */; }; + D0C26D691FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D681FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift */; }; + D0C26D6A1FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D681FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift */; }; + D0C26D6C1FE286C3004ABF18 /* FetchChatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D6B1FE286C3004ABF18 /* FetchChatList.swift */; }; + D0C26D6D1FE286C3004ABF18 /* FetchChatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C26D6B1FE286C3004ABF18 /* FetchChatList.swift */; }; + D0C27B3F1F4B51D000A4E170 /* CachedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B3E1F4B51D000A4E170 /* CachedStickerPack.swift */; }; + D0C27B401F4B51D000A4E170 /* CachedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B3E1F4B51D000A4E170 /* CachedStickerPack.swift */; }; + D0C27B421F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B411F4B58C000A4E170 /* PeerSpecificStickerPack.swift */; }; + D0C27B431F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B411F4B58C000A4E170 /* PeerSpecificStickerPack.swift */; }; + D0C44B611FC616E200227BE0 /* SearchGroupMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C44B601FC616E200227BE0 /* SearchGroupMembers.swift */; }; + D0C44B621FC616E200227BE0 /* SearchGroupMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C44B601FC616E200227BE0 /* SearchGroupMembers.swift */; }; + D0C48F391E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */; }; + D0C48F3A1E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */; }; + D0C48F3C1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */; }; + D0C48F3D1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */; }; + D0C50E341E93A86600F62E39 /* CallSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E331E93A86600F62E39 /* CallSessionManager.swift */; }; + D0C50E351E93A86600F62E39 /* CallSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E331E93A86600F62E39 /* CallSessionManager.swift */; }; + D0CA3F84207391560042D2B6 /* SecureIdPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CA3F83207391560042D2B6 /* SecureIdPadding.swift */; }; + D0CA3F85207391560042D2B6 /* SecureIdPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CA3F83207391560042D2B6 /* SecureIdPadding.swift */; }; + D0CA8E4B227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CA8E4A227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift */; }; + D0CA8E4C227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CA8E4A227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift */; }; + D0CAF2EA1D75EC600011F558 /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CAF2E91D75EC600011F558 /* MtProtoKitDynamic.framework */; }; + D0D1026C2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */; }; + D0D1026D2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */; }; + D0D748021E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; }; + D0D748031E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; }; + D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */; }; + D0DA1D331F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */; }; + D0DB7F031F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DB7F021F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift */; }; + D0DB7F041F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DB7F021F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift */; }; + D0DC354E1DE368F7000195EB /* RequestChatContextResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */; }; + D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC354F1DE36900000195EB /* ChatContextResult.swift */; }; + D0DC35511DE36908000195EB /* RequestChatContextResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */; }; + D0DC35521DE36908000195EB /* ChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC354F1DE36900000195EB /* ChatContextResult.swift */; }; + D0DF0C8A1D819C7E008AEB01 /* JoinChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C891D819C7E008AEB01 /* JoinChannel.swift */; }; + D0DF0C911D81A857008AEB01 /* ImageRepresentationsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */; }; + D0DF0C931D81AD09008AEB01 /* MessageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */; }; + D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */; }; + D0DFD5DF1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DFD5DE1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift */; }; + D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DFD5DE1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift */; }; + D0E23DD51E8042F500B9B6D2 /* FeaturedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DD41E8042F500B9B6D2 /* FeaturedStickerPack.swift */; }; + D0E23DD61E8042F500B9B6D2 /* FeaturedStickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DD41E8042F500B9B6D2 /* FeaturedStickerPack.swift */; }; + D0E23DDA1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DD91E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift */; }; + D0E23DDB1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DD91E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift */; }; + D0E23DDF1E8082A400B9B6D2 /* ArchivedStickerPacks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DDE1E8082A400B9B6D2 /* ArchivedStickerPacks.swift */; }; + D0E23DE01E8082A400B9B6D2 /* ArchivedStickerPacks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E23DDE1E8082A400B9B6D2 /* ArchivedStickerPacks.swift */; }; + D0E305A71E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E305A61E5B5CBE00D7A3A2 /* PeerAdmins.swift */; }; + D0E305A81E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E305A61E5B5CBE00D7A3A2 /* PeerAdmins.swift */; }; + D0E305AA1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E305A91E5BA02D00D7A3A2 /* ChannelBlacklist.swift */; }; + D0E305AB1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E305A91E5BA02D00D7A3A2 /* ChannelBlacklist.swift */; }; + D0E35A0E1DE4953E00BC6096 /* FetchHttpResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0D1DE4953E00BC6096 /* FetchHttpResource.swift */; }; + D0E35A101DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */; }; + D0E35A121DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */; }; + D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */; }; + D0E35A141DE4C69C00BC6096 /* FetchHttpResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0D1DE4953E00BC6096 /* FetchHttpResource.swift */; }; + D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */; }; + D0E412D7206A866B00BEE4A2 /* UploadSecureIdFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412D6206A866B00BEE4A2 /* UploadSecureIdFile.swift */; }; + D0E412D8206A866B00BEE4A2 /* UploadSecureIdFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412D6206A866B00BEE4A2 /* UploadSecureIdFile.swift */; }; + D0E412DC206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412DB206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift */; }; + D0E412DD206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412DB206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift */; }; + D0E412E1206AB24700BEE4A2 /* SecureFileMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E0206AB24700BEE4A2 /* SecureFileMediaResource.swift */; }; + D0E412E2206AB24700BEE4A2 /* SecureFileMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E0206AB24700BEE4A2 /* SecureFileMediaResource.swift */; }; + D0E412E7206ABC7500BEE4A2 /* EncryptedMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E6206ABC7500BEE4A2 /* EncryptedMediaResource.swift */; }; + D0E412E8206ABC7500BEE4A2 /* EncryptedMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E6206ABC7500BEE4A2 /* EncryptedMediaResource.swift */; }; + D0E412EA206AD18E00BEE4A2 /* DecryptedResourceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E9206AD18E00BEE4A2 /* DecryptedResourceData.swift */; }; + D0E412EB206AD18E00BEE4A2 /* DecryptedResourceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412E9206AD18E00BEE4A2 /* DecryptedResourceData.swift */; }; + D0E412EE206AF65500BEE4A2 /* GrantSecureIdAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412ED206AF65500BEE4A2 /* GrantSecureIdAccess.swift */; }; + D0E412EF206AF65500BEE4A2 /* GrantSecureIdAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412ED206AF65500BEE4A2 /* GrantSecureIdAccess.swift */; }; + D0E412F1206B9BB700BEE4A2 /* SecureIdPassportValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412F0206B9BB700BEE4A2 /* SecureIdPassportValue.swift */; }; + D0E412F2206B9BB700BEE4A2 /* SecureIdPassportValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412F0206B9BB700BEE4A2 /* SecureIdPassportValue.swift */; }; + D0E412F4206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412F3206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift */; }; + D0E412F5206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E412F3206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift */; }; + D0E41301206B9E6E00BEE4A2 /* SecureIdAddressValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E41300206B9E6E00BEE4A2 /* SecureIdAddressValue.swift */; }; + D0E41302206B9E6E00BEE4A2 /* SecureIdAddressValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E41300206B9E6E00BEE4A2 /* SecureIdAddressValue.swift */; }; + D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; }; + D0E652201E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; }; + D0E68775207534CA0064BDB2 /* Api0.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E68768207534C90064BDB2 /* Api0.swift */; }; + D0E68776207534CA0064BDB2 /* Api0.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E68768207534C90064BDB2 /* Api0.swift */; }; + D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; }; + D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; }; + D0E8B8B32044706300605593 /* ForwardGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8B8B22044706300605593 /* ForwardGame.swift */; }; + D0E8B8B42044706300605593 /* ForwardGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8B8B22044706300605593 /* ForwardGame.swift */; }; + D0EA188220D3D2B1001AEE19 /* RemoteStorageConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EA188120D3D2B1001AEE19 /* RemoteStorageConfiguration.swift */; }; + D0EC559A2101ED0800D1992C /* DeleteMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC55992101ED0800D1992C /* DeleteMessages.swift */; }; + D0EC559B2101ED0800D1992C /* DeleteMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC55992101ED0800D1992C /* DeleteMessages.swift */; }; + D0EE7FC120986BF400981319 /* SecureIdInternalPassportValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC020986BF400981319 /* SecureIdInternalPassportValue.swift */; }; + D0EE7FC220986BF400981319 /* SecureIdInternalPassportValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC020986BF400981319 /* SecureIdInternalPassportValue.swift */; }; + D0EE7FC420986C5300981319 /* SecureIdPassportRegistrationValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC320986C5300981319 /* SecureIdPassportRegistrationValue.swift */; }; + D0EE7FC520986C5300981319 /* SecureIdPassportRegistrationValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC320986C5300981319 /* SecureIdPassportRegistrationValue.swift */; }; + D0EE7FC72098853100981319 /* SecureIdTemporaryRegistrationValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC62098853100981319 /* SecureIdTemporaryRegistrationValue.swift */; }; + D0EE7FC82098853100981319 /* SecureIdTemporaryRegistrationValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE7FC62098853100981319 /* SecureIdTemporaryRegistrationValue.swift */; }; + D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; }; + D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; }; + D0F19F6620E6620D00EEC860 /* MultiplexedRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F19F6520E6620D00EEC860 /* MultiplexedRequestManager.swift */; }; + D0F19F6720E6621000EEC860 /* MultiplexedRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F19F6520E6620D00EEC860 /* MultiplexedRequestManager.swift */; }; + D0F3A89F1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; }; + D0F3A8A01E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; }; + D0F3A8A21E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */; }; + D0F3A8A31E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */; }; + D0F3A8A51E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A41E82C94C00B4C64C /* SynchronizeableChatInputState.swift */; }; + D0F3A8A61E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A41E82C94C00B4C64C /* SynchronizeableChatInputState.swift */; }; + D0F3A8A81E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A71E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift */; }; + D0F3A8A91E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A71E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift */; }; + D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D711D631ABA00955575 /* SearchMessages.swift */; }; + D0F3CC7A1DDE2859008148FA /* RequestMessageActionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */; }; + D0F3CC7B1DDE2859008148FA /* RequestEditMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */; }; + D0F3CC7D1DDE289E008148FA /* ResolvePeerByName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC7C1DDE289E008148FA /* ResolvePeerByName.swift */; }; + D0F53BE91E784A4800117362 /* ChangeAccountPhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F53BE81E784A4800117362 /* ChangeAccountPhoneNumber.swift */; }; + D0F53BEA1E784A4800117362 /* ChangeAccountPhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F53BE81E784A4800117362 /* ChangeAccountPhoneNumber.swift */; }; + D0F760D822202FE20074F7E5 /* ChannelStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F760D722202FE20074F7E5 /* ChannelStats.swift */; }; + D0F760D922202FE20074F7E5 /* ChannelStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F760D722202FE20074F7E5 /* ChannelStats.swift */; }; + D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */; }; + D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */; }; + D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */; }; + D0F7AB301DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */; }; + D0F7B1E31E045C7B007EB8A5 /* RichText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827CA1E02F5B200071108 /* RichText.swift */; }; + D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827C81E02F59C00071108 /* InstantPage.swift */; }; + D0F7B1E71E045C87007EB8A5 /* JoinChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C891D819C7E008AEB01 /* JoinChannel.swift */; }; + D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */; }; + D0F7B1E91E045C87007EB8A5 /* PeerCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */; }; + D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843961DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift */; }; + D0F7B1EB1E045C87007EB8A5 /* ResolvePeerByName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC7C1DDE289E008148FA /* ResolvePeerByName.swift */; }; + D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827BA1E00451F00071108 /* SearchPeers.swift */; }; + D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */; }; + D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */; }; + D0F8C3A02017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */; }; + D0F8C3A12017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */; }; + D0FA08BB2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA08BA2046B37900DD23FC /* ContentPrivacySettings.swift */; }; + D0FA08BC2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA08BA2046B37900DD23FC /* ContentPrivacySettings.swift */; }; + D0FA0ABD1E76C908005BB9B7 /* TwoStepVerification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */; }; + D0FA35051EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */; }; + D0FA35061EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */; }; + D0FA35081EA632E400E56FFA /* CollectCacheUsageStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35071EA632E400E56FFA /* CollectCacheUsageStats.swift */; }; + D0FA35091EA632E400E56FFA /* CollectCacheUsageStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35071EA632E400E56FFA /* CollectCacheUsageStats.swift */; }; + D0FA8B981E1E955C001E855B /* SecretChatOutgoingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8B971E1E955C001E855B /* SecretChatOutgoingOperation.swift */; }; + D0FA8B991E1E955C001E855B /* SecretChatOutgoingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8B971E1E955C001E855B /* SecretChatOutgoingOperation.swift */; }; + D0FA8B9E1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8B9D1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift */; }; + D0FA8B9F1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8B9D1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift */; }; + D0FA8BA11E1F99E1001E855B /* SecretChatFileReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA01E1F99E1001E855B /* SecretChatFileReference.swift */; }; + D0FA8BA21E1F99E1001E855B /* SecretChatFileReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA01E1F99E1001E855B /* SecretChatFileReference.swift */; }; + D0FA8BA41E1FA341001E855B /* SecretChatKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA31E1FA341001E855B /* SecretChatKeychain.swift */; }; + D0FA8BA51E1FA341001E855B /* SecretChatKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA31E1FA341001E855B /* SecretChatKeychain.swift */; }; + D0FA8BA71E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA61E1FA6DF001E855B /* TelegramSecretChat.swift */; }; + D0FA8BA81E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA61E1FA6DF001E855B /* TelegramSecretChat.swift */; }; + D0FA8BAA1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA91E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift */; }; + D0FA8BAB1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BA91E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift */; }; + D0FA8BAD1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BAC1E1FD6E2001E855B /* MemoryBufferExtensions.swift */; }; + D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BAC1E1FD6E2001E855B /* MemoryBufferExtensions.swift */; }; + D0FA8BB01E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BAF1E1FEC7E001E855B /* SecretChatEncryptionConfig.swift */; }; + D0FA8BB11E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BAF1E1FEC7E001E855B /* SecretChatEncryptionConfig.swift */; }; + D0FA8BB31E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB21E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift */; }; + D0FA8BB41E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB21E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift */; }; + D0FA8BB61E223C16001E855B /* SecretApiLayer8.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB51E223C16001E855B /* SecretApiLayer8.swift */; }; + D0FA8BB71E223C16001E855B /* SecretApiLayer8.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB51E223C16001E855B /* SecretApiLayer8.swift */; }; + D0FA8BB91E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB81E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift */; }; + D0FA8BBA1E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA8BB81E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift */; }; + D0FC195B2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FC195A2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift */; }; + D0FC195C2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FC195A2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + D09D8C0C1D4FAB1D0081DBEC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D09D8BF81D4FAB1D0081DBEC /* Project object */; + proxyType = 1; + remoteGlobalIDString = D09D8C001D4FAB1D0081DBEC; + remoteInfo = TelegramCore; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0900555521E4A96D0030924C /* Wallpaper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallpaper.swift; sourceTree = ""; }; + 09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedVoipConfigurationUpdates.swift; sourceTree = ""; }; + 090E778222A9862100CD99F5 /* ChannelOwnershipTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelOwnershipTransfer.swift; sourceTree = ""; }; + 090E778F22AAABC600CD99F5 /* PeersNearby.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeersNearby.swift; sourceTree = ""; }; + 093857A62243D87800EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeEmojiKeywordsOperations.swift; sourceTree = ""; }; + 093857A72243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeEmojiKeywordsOperation.swift; sourceTree = ""; }; + 093857AA2243D88C00EB6A54 /* EmojiKeywords.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiKeywords.swift; sourceTree = ""; }; + 0962E66621B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAppConfigurationUpdates.swift; sourceTree = ""; }; + 0962E66821B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeAppLogEventsOperation.swift; sourceTree = ""; }; + 0962E66A21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeAppLogEventsOperations.swift; sourceTree = ""; }; + 0962E66C21B5C56F00245FD9 /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = ""; }; + 0962E66E21B6147600245FD9 /* AppConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfiguration.swift; sourceTree = ""; }; + 0962E67421B6437600245FD9 /* SplitTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitTest.swift; sourceTree = ""; }; + 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBotsConfiguration.swift; sourceTree = ""; }; + 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutodownloadSettings.swift; sourceTree = ""; }; + 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAutodownloadSettingsUpdates.swift; sourceTree = ""; }; + 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExceptionsList.swift; sourceTree = ""; }; + 9FC8ADAA206BBFF10094F7B4 /* RecentWebSessions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentWebSessions.swift; sourceTree = ""; }; + C205FEA71EB3B75900455808 /* ExportMessageLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportMessageLink.swift; sourceTree = ""; }; + C210DD611FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceReferenceMessageAttribute.swift; sourceTree = ""; }; + C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleChannelSignatures.swift; sourceTree = ""; }; + C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelAdminEventLogs.swift; sourceTree = ""; }; + C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupReturnAndLeft.swift; sourceTree = ""; }; + C2366C851E4F403C0097CCFF /* AddressNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressNames.swift; sourceTree = ""; }; + C2366C881E4F40480097CCFF /* SupportPeerId.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportPeerId.swift; sourceTree = ""; }; + C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadMessagesIfNecessary.swift; sourceTree = ""; }; + C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePinnedMessage.swift; sourceTree = ""; }; + C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportContact.swift; sourceTree = ""; }; + C251D7421E65E50500283EDE /* StickerSetInstallation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerSetInstallation.swift; sourceTree = ""; }; + C28725411EF967E700613564 /* NotificationInfoMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationInfoMessageAttribute.swift; sourceTree = ""; }; + C28D3CEF20D3DA900027F4D6 /* DeepLinkInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkInfo.swift; sourceTree = ""; }; + C29340F21F5080FA0074991E /* UpdateGroupSpecificStickerset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateGroupSpecificStickerset.swift; sourceTree = ""; }; + C2E064671ECEEF0A00387BB8 /* TelegramMediaInvoice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaInvoice.swift; sourceTree = ""; }; + C2E0646C1ECF171D00387BB8 /* TelegramMediaWebDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaWebDocument.swift; sourceTree = ""; }; + C2F4ED1C1EC60064005F2696 /* RateCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RateCall.swift; sourceTree = ""; }; + C2FD33E01E680E9E008D13D4 /* RequestUserPhotos.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestUserPhotos.swift; sourceTree = ""; }; + C2FD33E31E687BF1008D13D4 /* PeerPhotoUpdater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerPhotoUpdater.swift; sourceTree = ""; }; + C2FD33EA1E696C78008D13D4 /* GroupsInCommon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsInCommon.swift; sourceTree = ""; }; + D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = ""; }; + D00422D221677F4500719B67 /* ManagedAccountPresence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAccountPresence.swift; sourceTree = ""; }; + D00580AD21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountEnvironmentAttribute.swift; sourceTree = ""; }; + D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramChannelAdminRights.swift; sourceTree = ""; }; + D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramChannelBannedRights.swift; sourceTree = ""; }; + D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedChannelParticipants.swift; sourceTree = ""; }; + D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkMessageContentAsConsumedInteractively.swift; sourceTree = ""; }; + D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetSecretChatMessageAutoremoveTimeoutInteractively.swift; sourceTree = ""; }; + D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TeleramMediaUnsupported.swift; sourceTree = ""; }; + D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaGame.swift; sourceTree = ""; }; + D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsumableContentMessageAttribute.swift; sourceTree = ""; }; + D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeConsumeMessageContentsOperations.swift; sourceTree = ""; }; + D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeConsumeMessageContentsOperation.swift; sourceTree = ""; }; + D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerInputActivity.swift; sourceTree = ""; }; + D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerInputActivityManager.swift; sourceTree = ""; }; + D00DBBD61E64E41100DB5485 /* CreateSecretChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateSecretChat.swift; sourceTree = ""; }; + D00DBBD91E64E67E00DB5485 /* UpdateSecretChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateSecretChat.swift; sourceTree = ""; }; + D0119CAF20CA9EA800895300 /* MarkAllChatsAsRead.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkAllChatsAsRead.swift; sourceTree = ""; }; + D0136308208F3B0900EB3653 /* SecureIdValueContentError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdValueContentError.swift; sourceTree = ""; }; + D015E00D225CA61100CB9E8A /* FindChannelById.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindChannelById.swift; sourceTree = ""; }; + D01749581E1092BC0057C89A /* RequestStartBot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestStartBot.swift; sourceTree = ""; }; + D017495D1E118F790057C89A /* AccountStateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManager.swift; sourceTree = ""; }; + D017495F1E118FC30057C89A /* AccountIntermediateState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountIntermediateState.swift; sourceTree = ""; }; + D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatState.swift; sourceTree = ""; }; + D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmTwoStepRecoveryEmail.swift; sourceTree = ""; }; + D018D3361E648ACF00C5E089 /* ChannelCreation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelCreation.swift; sourceTree = ""; }; + D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer73.swift; sourceTree = ""; }; + D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretChatLayerNegotiation.swift; sourceTree = ""; }; + D018EE042045E95000CBB130 /* CheckPeerChatServiceActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckPeerChatServiceActions.swift; sourceTree = ""; }; + D019B1CB1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatRekeySession.swift; sourceTree = ""; }; + D01A21A51F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeSavedStickersOperation.swift; sourceTree = ""; }; + D01A21A81F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeSavedStickersOperations.swift; sourceTree = ""; }; + D01A21AB1F38D10E00DDA104 /* SavedStickerItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SavedStickerItem.swift; sourceTree = ""; }; + D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestMessageActionCallback.swift; sourceTree = ""; }; + D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestEditMessage.swift; sourceTree = ""; }; + D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplyUpdateMessage.swift; sourceTree = ""; }; + D01B27A11E394D8B0022A4C0 /* PrivacySettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = ""; }; + D01C06B61FBBA269001561AB /* CanSendMessagesToPeer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CanSendMessagesToPeer.swift; sourceTree = ""; }; + D01C7ED21EF5DF83008305F1 /* LimitsConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LimitsConfiguration.swift; sourceTree = ""; }; + D01C7ED51EF5E468008305F1 /* ProxySettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxySettings.swift; sourceTree = ""; }; + D01C7F031EFC1C49008305F1 /* DeviceContact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceContact.swift; sourceTree = ""; }; + D01D6BF81E42A713006151C6 /* SearchStickers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchStickers.swift; sourceTree = ""; }; + D021E0DE1DB539FC00C6B04F /* StickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerPack.swift; sourceTree = ""; }; + D021E0E11DB5401A00C6B04F /* StickerManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerManagement.swift; sourceTree = ""; }; + D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResourceNetworkStatsTag.swift; sourceTree = ""; }; + D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaResource.swift; sourceTree = ""; }; + D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelHistoryAvailabilitySettings.swift; sourceTree = ""; }; + D023E67721540624008C27D1 /* UpdateMessageMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateMessageMedia.swift; sourceTree = ""; }; + D026099D20C695AF006C34AC /* Wallpapers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallpapers.swift; sourceTree = ""; }; + D02609BB20C6EB97006C34AC /* Crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Crypto.h; sourceTree = ""; }; + D02609BE20C6EC08006C34AC /* Crypto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Crypto.m; sourceTree = ""; }; + D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteMessagesInteractively.swift; sourceTree = ""; }; + D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudChatRemoveMessagesOperation.swift; sourceTree = ""; }; + D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedCloudChatRemoveMessagesOperations.swift; sourceTree = ""; }; + D02B198F21FB1D520094A764 /* RegisterNotificationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterNotificationToken.swift; sourceTree = ""; }; + D02D60A6206BA5F900FEFE1E /* SecureIdValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdValue.swift; sourceTree = ""; }; + D02D60AA206BA64100FEFE1E /* VerifySecureIdValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifySecureIdValue.swift; sourceTree = ""; }; + D02DADC02139A1FC00116225 /* ContactSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSyncManager.swift; sourceTree = ""; }; + D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramPeerNotificationSettings.swift; sourceTree = ""; }; + D032F5BB20EF84FD00037B6C /* FetchedMediaResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchedMediaResource.swift; sourceTree = ""; }; + D033873F223BD48B007A2CE4 /* ContactsSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsSettings.swift; sourceTree = ""; }; + D0338742223BD532007A2CE4 /* InitializeAccountAfterLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializeAccountAfterLogin.swift; sourceTree = ""; }; + D033FEAF1E61EB0200644997 /* PeerContactSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerContactSettings.swift; sourceTree = ""; }; + D033FEB21E61F3C000644997 /* ReportPeer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportPeer.swift; sourceTree = ""; }; + D033FEB51E61F3F900644997 /* BlockedPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockedPeers.swift; sourceTree = ""; }; + D0380DB9204EF306000414AB /* MessageMediaPreuploadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageMediaPreuploadManager.swift; sourceTree = ""; }; + D03B0CB81D62233400955575 /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; }; + D03B0CBC1D62234300955575 /* Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; }; + D03B0CBE1D62234A00955575 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; + D03B0CC01D62235000955575 /* StringFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringFormat.swift; sourceTree = ""; }; + D03B0CCD1D62239600955575 /* PhoneNumbers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumbers.swift; sourceTree = ""; }; + D03B0CD21D62244300955575 /* Namespaces.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Namespaces.swift; sourceTree = ""; }; + D03B0CD41D62245300955575 /* TelegramUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramUser.swift; sourceTree = ""; }; + D03B0CD51D62245300955575 /* TelegramGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramGroup.swift; sourceTree = ""; }; + D03B0CD81D62245B00955575 /* PeerUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerUtils.swift; sourceTree = ""; }; + D03B0CDA1D62245F00955575 /* ApiUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiUtils.swift; sourceTree = ""; }; + D03B0CDF1D62249100955575 /* StoreMessage_Telegram.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreMessage_Telegram.swift; sourceTree = ""; }; + D03B0CE11D62249B00955575 /* InlineBotMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InlineBotMessageAttribute.swift; sourceTree = ""; }; + D03B0CE31D62249F00955575 /* TextEntitiesMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEntitiesMessageAttribute.swift; sourceTree = ""; }; + D03B0CE51D6224A700955575 /* ReplyMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyMessageAttribute.swift; sourceTree = ""; }; + D03B0CE71D6224AD00955575 /* ViewCountMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewCountMessageAttribute.swift; sourceTree = ""; }; + D03B0CEC1D62250800955575 /* TelegramMediaAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaAction.swift; sourceTree = ""; }; + D03B0CED1D62250800955575 /* TelegramMediaContact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaContact.swift; sourceTree = ""; }; + D03B0CEE1D62250800955575 /* TelegramMediaFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaFile.swift; sourceTree = ""; }; + D03B0CEF1D62250800955575 /* TelegramMediaImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaImage.swift; sourceTree = ""; }; + D03B0CF11D62250800955575 /* TelegramMediaMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaMap.swift; sourceTree = ""; }; + D03B0CF31D62250800955575 /* TelegramMediaWebpage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaWebpage.swift; sourceTree = ""; }; + D03B0CFF1D62255C00955575 /* ChannelState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelState.swift; sourceTree = ""; }; + D03B0D001D62255C00955575 /* EnqueueMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnqueueMessage.swift; sourceTree = ""; }; + D03B0D011D62255C00955575 /* Holes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Holes.swift; sourceTree = ""; }; + D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManagementUtils.swift; sourceTree = ""; }; + D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadState.swift; sourceTree = ""; }; + D03B0D051D62255C00955575 /* UpdateGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateGroup.swift; sourceTree = ""; }; + D03B0D061D62255C00955575 /* UpdateMessageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateMessageService.swift; sourceTree = ""; }; + D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatesApiUtils.swift; sourceTree = ""; }; + D03B0D391D6319E200955575 /* Fetch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetch.swift; sourceTree = ""; }; + D03B0D431D6319F900955575 /* CloudFileMediaResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudFileMediaResource.swift; sourceTree = ""; }; + D03B0D551D631A6900955575 /* Buffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Buffer.swift; sourceTree = ""; }; + D03B0D561D631A6900955575 /* Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Download.swift; sourceTree = ""; }; + D03B0D571D631A6900955575 /* MultipartFetch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartFetch.swift; sourceTree = ""; }; + D03B0D581D631A6900955575 /* Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; + D03B0D591D631A6900955575 /* Serialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = ""; }; + D03B0D611D631A8B00955575 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; + D03B0D631D631A8B00955575 /* AccountViewTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountViewTracker.swift; sourceTree = ""; }; + D03B0D641D631A8B00955575 /* RecentPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentPeers.swift; sourceTree = ""; }; + D03B0D6C1D631AA300955575 /* ContactManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactManagement.swift; sourceTree = ""; }; + D03B0D711D631ABA00955575 /* SearchMessages.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchMessages.swift; sourceTree = ""; }; + D03B0E411D631E6600955575 /* NetworkLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkLogging.h; sourceTree = ""; }; + D03B0E421D631E6600955575 /* NetworkLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkLogging.m; sourceTree = ""; }; + D03B0E571D631EB900955575 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; + D03B0E591D63215200955575 /* TelegramCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = TelegramCore.xcconfig; path = TelegramCore/Config/TelegramCore.xcconfig; sourceTree = ""; }; + D03B0E5B1D63240700955575 /* TelegramCoreIncludes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TelegramCoreIncludes.h; sourceTree = ""; }; + D03B0E5D1D6327F600955575 /* SSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D03B0E5F1D6327FF00955575 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + D03B0E611D63281A00955575 /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = "third-party/FFmpeg-iOS/lib/libavcodec.a"; sourceTree = ""; }; + D03B0E621D63281A00955575 /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavformat.a; path = "third-party/FFmpeg-iOS/lib/libavformat.a"; sourceTree = ""; }; + D03B0E631D63281A00955575 /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavutil.a; path = "third-party/FFmpeg-iOS/lib/libavutil.a"; sourceTree = ""; }; + D03B0E641D63281A00955575 /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswresample.a; path = "third-party/FFmpeg-iOS/lib/libswresample.a"; sourceTree = ""; }; + D03B0E691D63283000955575 /* libwebp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebp.a; path = "third-party/libwebp/lib/libwebp.a"; sourceTree = ""; }; + D03B0E6B1D63283C00955575 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; + D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartUpload.swift; sourceTree = ""; }; + D03DC90F1F82E344001D584C /* AccountStateReset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStateReset.swift; sourceTree = ""; }; + D03DC9121F82F89D001D584C /* RegularChatState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegularChatState.swift; sourceTree = ""; }; + D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutAccountAttribute.swift; sourceTree = ""; }; + D041E3F41E535464008C24B4 /* AddPeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPeerMember.swift; sourceTree = ""; }; + D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePeerMember.swift; sourceTree = ""; }; + D042C6821E8D9DF800C863B0 /* Unixtime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unixtime.swift; sourceTree = ""; }; + D0439B5C228ECB270067E026 /* RequestPhoneNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestPhoneNumber.swift; sourceTree = ""; }; + D0439B5F228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentRequiresValidationMessageAttribute.swift; sourceTree = ""; }; + D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcessSecretChatIncomingDecryptedOperations.swift; sourceTree = ""; }; + D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatEncryption.swift; sourceTree = ""; }; + D0448C981E268F9A005A61A7 /* SecretApiLayer46.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer46.swift; sourceTree = ""; }; + D0448C9E1E27F5EB005A61A7 /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; + D0448CA11E291B14005A61A7 /* FetchSecretFileResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchSecretFileResource.swift; sourceTree = ""; }; + D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResourceApiUtils.swift; sourceTree = ""; }; + D04554A521B43440007A6DD9 /* CancelAccountReset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelAccountReset.swift; sourceTree = ""; }; + D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingContentInfoMessageAttribute.swift; sourceTree = ""; }; + D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeMarkAllUnseenPersonalMessagesOperation.swift; sourceTree = ""; }; + D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift; sourceTree = ""; }; + D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedProxyInfoUpdates.swift; sourceTree = ""; }; + D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentMediaItem.swift; sourceTree = ""; }; + D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedRecentStickers.swift; sourceTree = ""; }; + D049EAE71E44B67100A2CD3A /* RecentPeerItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentPeerItem.swift; sourceTree = ""; }; + D049EAEA1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentlySearchedPeerIds.swift; sourceTree = ""; }; + D049EAF41E44DF3300A2CD3A /* AccountState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountState.swift; sourceTree = ""; }; + D04CAA591E83310D0047E51F /* MD5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MD5.swift; sourceTree = ""; }; + D04D8FF3209A4B0700865719 /* NetworkSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkSettings.swift; sourceTree = ""; }; + D050F20F1E48AB0600988324 /* InteractivePhoneFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractivePhoneFormatter.swift; sourceTree = ""; }; + D050F2501E4A59C200988324 /* JoinLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JoinLink.swift; sourceTree = ""; }; + D051DB13215EC5A300F30F92 /* AppChangelogState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppChangelogState.swift; sourceTree = ""; }; + D051DB16215ECC4D00F30F92 /* AppChangelog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppChangelog.swift; sourceTree = ""; }; + D0528E591E658B3600E2FEF5 /* ManagedLocalInputActivities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedLocalInputActivities.swift; sourceTree = ""; }; + D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleMessageView.swift; sourceTree = ""; }; + D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateContactName.swift; sourceTree = ""; }; + D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebpagePreview.swift; sourceTree = ""; }; + D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeRecentlyUsedMediaOperations.swift; sourceTree = ""; }; + D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeRecentlyUsedMediaOperations.swift; sourceTree = ""; }; + D053B3F91F1651FA00E2D58A /* MonotonicTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MonotonicTime.h; sourceTree = ""; }; + D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MonotonicTime.m; sourceTree = ""; }; + D053B3FD1F16534400E2D58A /* MonotonicTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonotonicTime.swift; sourceTree = ""; }; + D053B4171F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthorSignatureMessageAttribute.swift; sourceTree = ""; }; + D053B41A1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaExpiredContent.swift; sourceTree = ""; }; + D05452061E7B5093006EEF19 /* LoadedStickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadedStickerPack.swift; sourceTree = ""; }; + D054648A2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPersonalDetailsValue.swift; sourceTree = ""; }; + D054648D20738626002ECC1E /* SecureIdDriversLicenseValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdDriversLicenseValue.swift; sourceTree = ""; }; + D054649020738653002ECC1E /* SecureIdIDCardValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdIDCardValue.swift; sourceTree = ""; }; + D0546493207386D7002ECC1E /* SecureIdUtilityBillValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdUtilityBillValue.swift; sourceTree = ""; }; + D05464962073872C002ECC1E /* SecureIdBankStatementValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdBankStatementValue.swift; sourceTree = ""; }; + D054649920738760002ECC1E /* SecureIdRentalAgreementValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdRentalAgreementValue.swift; sourceTree = ""; }; + D0561DE21E5737FC00E6B9E9 /* UpdatePeerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePeerInfo.swift; sourceTree = ""; }; + D0561DE91E5754FA00E6B9E9 /* ChannelAdmins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelAdmins.swift; sourceTree = ""; }; + D0575AF01E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeSavedGifsOperation.swift; sourceTree = ""; }; + D0575AF31E9FFDDD006F2541 /* ManagedSynchronizeSavedGifsOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeSavedGifsOperations.swift; sourceTree = ""; }; + D058E0D01E8AD65C00A442DE /* StandaloneSendMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandaloneSendMessage.swift; sourceTree = ""; }; + D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatedAccountPrivacySettings.swift; sourceTree = ""; }; + D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSessions.swift; sourceTree = ""; }; + D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentAccountSession.swift; sourceTree = ""; }; + D05D8B362192F8AF0064586F /* LocalizationListState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationListState.swift; sourceTree = ""; }; + D0613FC91E60440600202CDB /* InvitationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitationLinks.swift; sourceTree = ""; }; + D0613FCE1E60520700202CDB /* ChannelMembers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMembers.swift; sourceTree = ""; }; + D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertGroupToSupergroup.swift; sourceTree = ""; }; + D0633CD12253A528003DD95F /* ChatOnlineMembers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatOnlineMembers.swift; sourceTree = ""; }; + D0633CDA2253C0D3003DD95F /* CloudMediaResourceParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudMediaResourceParameters.swift; sourceTree = ""; }; + D0642EF81F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EarliestUnseenPersonalMentionMessage.swift; sourceTree = ""; }; + D06706641D512ADB00DED3E3 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D06706651D512ADB00DED3E3 /* Display.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D06706671D512ADB00DED3E3 /* Postbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Postbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D06706681D512ADB00DED3E3 /* SwiftSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D067066E1D512AEB00DED3E3 /* MtProtoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MtProtoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D06AFE8820BF66BF00EA5124 /* DeserializeFunctionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeserializeFunctionResponse.swift; sourceTree = ""; }; + D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedNotificationSettingsBehaviors.swift; sourceTree = ""; }; + D06ECFC720B810D300C576C2 /* TermsOfService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfService.swift; sourceTree = ""; }; + D07047B31F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsumablePersonalMentionMessageAttribute.swift; sourceTree = ""; }; + D07047B61F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedConsumePersonalMessagesActions.swift; sourceTree = ""; }; + D07047B91F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsumePersonalMessageAction.swift; sourceTree = ""; }; + D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForwardSourceInfoAttribute.swift; sourceTree = ""; }; + D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingMessageInfoAttribute.swift; sourceTree = ""; }; + D0754D291EEE10FC00884F6E /* BotPaymentForm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BotPaymentForm.swift; sourceTree = ""; }; + D076F8882296D8E9004F895A /* ManageChannelDiscussionGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageChannelDiscussionGroup.swift; sourceTree = ""; }; + D07827BA1E00451F00071108 /* SearchPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchPeers.swift; sourceTree = ""; }; + D07827C81E02F59C00071108 /* InstantPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstantPage.swift; sourceTree = ""; }; + D07827CA1E02F5B200071108 /* RichText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RichText.swift; sourceTree = ""; }; + D07E413E208A769D00FCA8F0 /* ProxyServersStatuses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyServersStatuses.swift; sourceTree = ""; }; + D081E109217F5ADE003CD921 /* LocalizationPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationPreview.swift; sourceTree = ""; }; + D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedGlobalNotificationSettings.swift; sourceTree = ""; }; + D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalNotificationSettings.swift; sourceTree = ""; }; + D08984F12114B97400918162 /* ClearCloudDrafts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearCloudDrafts.swift; sourceTree = ""; }; + D08984F421187ECA00918162 /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = ""; }; + D08984F72118816900918162 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = ""; }; + D08984F82118816A00918162 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = ""; }; + D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationSettings.swift; sourceTree = ""; }; + D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestedLocalizationEntry.swift; sourceTree = ""; }; + D08CAA831ED8164B0000FDA8 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; + D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationInfo.swift; sourceTree = ""; }; + D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localizations.swift; sourceTree = ""; }; + D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; + D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; + D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdDataTypes.swift; sourceTree = ""; }; + D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPhoneValue.swift; sourceTree = ""; }; + D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdEmailValue.swift; sourceTree = ""; }; + D093D805206539D000BC3599 /* SaveSecureIdValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveSecureIdValue.swift; sourceTree = ""; }; + D098907E22942E3B0053F151 /* ActiveSessionsContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionsContext.swift; sourceTree = ""; }; + D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMessageStateVersionAttribute.swift; sourceTree = ""; }; + D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryViewChannelStateValidation.swift; sourceTree = ""; }; + D099E221229420D600561B75 /* BlockedPeersContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedPeersContext.swift; sourceTree = ""; }; + D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = ""; }; + D09A2FE51D7CD4940018FB72 /* TelegramChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramChannel.swift; sourceTree = ""; }; + D09A2FEA1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerAccessRestrictionInfo.swift; sourceTree = ""; }; + D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PendingMessageManager.swift; sourceTree = ""; }; + D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PendingMessageUploadedContent.swift; sourceTree = ""; }; + D09D8C011D4FAB1D0081DBEC /* TelegramCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TelegramCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D09D8C041D4FAB1D0081DBEC /* TelegramCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TelegramCore.h; sourceTree = ""; }; + D09D8C051D4FAB1D0081DBEC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D09D8C0A1D4FAB1D0081DBEC /* TelegramCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TelegramCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D09D8C0F1D4FAB1D0081DBEC /* TelegramCoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TelegramCoreTests.m; sourceTree = ""; }; + D09D8C111D4FAB1D0081DBEC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D09F9DC520767D2C00DB4DE1 /* Api3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Api3.swift; sourceTree = ""; }; + D09F9DC620767D2C00DB4DE1 /* Api1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Api1.swift; sourceTree = ""; }; + D09F9DC720767D2C00DB4DE1 /* Api2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Api2.swift; sourceTree = ""; }; + D0A3E446214802C7008ACEF6 /* VoipConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipConfiguration.swift; sourceTree = ""; }; + D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadedPeer.swift; sourceTree = ""; }; + D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAutolockReportManager.swift; sourceTree = ""; }; + D0AAD1A71E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoremoveTimeoutMessageAttribute.swift; sourceTree = ""; }; + D0AAD1A91E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplyMaxReadIndexInteractively.swift; sourceTree = ""; }; + D0AAD1B71E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedAutoremoveMessageOperations.swift; sourceTree = ""; }; + D0AB0B911D65E9FA002C78E7 /* ManagedServiceViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedServiceViews.swift; sourceTree = ""; }; + D0AB0B931D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedMessageHistoryHoles.swift; sourceTree = ""; }; + D0AB0B951D662F0B002C78E7 /* ManagedChatListHoles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedChatListHoles.swift; sourceTree = ""; }; + D0AB0B991D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizePeerReadStates.swift; sourceTree = ""; }; + D0AB262521C2F991008F6685 /* TelegramMediaPoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelegramMediaPoll.swift; sourceTree = ""; }; + D0AB262A21C3CE80008F6685 /* Polls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Polls.swift; sourceTree = ""; }; + D0AC49491D7097A400AA55DA /* SSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0AD02E21FFFA14800C1DCFF /* PeerLiveLocationsContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerLiveLocationsContext.swift; sourceTree = ""; }; + D0ADF910212B00DD00310BBC /* SecureIdConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdConfiguration.swift; sourceTree = ""; }; + D0AF32211FAC95C20097362B /* StandaloneUploadedMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandaloneUploadedMedia.swift; sourceTree = ""; }; + D0AF32301FACEDEC0097362B /* CoreSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreSettings.swift; sourceTree = ""; }; + D0AF32341FAE8C6B0097362B /* MultipeerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipeerManager.swift; sourceTree = ""; }; + D0AF32371FAE8C910097362B /* MultipeerConnectivity.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultipeerConnectivity.framework; path = System/Library/Frameworks/MultipeerConnectivity.framework; sourceTree = SDKROOT; }; + D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHistoryPreloadManager.swift; sourceTree = ""; }; + D0B167221F9F972E00976B40 /* LoggingSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingSettings.swift; sourceTree = ""; }; + D0B2F7732052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelegramDeviceContactImportInfo.swift; sourceTree = ""; }; + D0B417C01D7DCEEF004562A4 /* ApiGroupOrChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiGroupOrChannel.swift; sourceTree = ""; }; + D0B418671D7E03D5004562A4 /* TelegramCoreMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TelegramCoreMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0B418691D7E03D5004562A4 /* TelegramCoreMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TelegramCoreMac.h; sourceTree = ""; }; + D0B4186A1D7E03D5004562A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D0B418701D7E0409004562A4 /* PostboxMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = PostboxMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0B418711D7E0409004562A4 /* SwiftSignalKitMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftSignalKitMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0B4187E1D7E054E004562A4 /* MtProtoKitMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MtProtoKitMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedUserData.swift; sourceTree = ""; }; + D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedGroupData.swift; sourceTree = ""; }; + D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedChannelData.swift; sourceTree = ""; }; + D0B843861DA6F705005F29E1 /* UpdateCachedPeerData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateCachedPeerData.swift; sourceTree = ""; }; + D0B843881DA7AB96005F29E1 /* ExportedInvitation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportedInvitation.swift; sourceTree = ""; }; + D0B8438B1DA7CF50005F29E1 /* BotInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BotInfo.swift; sourceTree = ""; }; + D0B8438D1DA7D296005F29E1 /* CachedGroupParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedGroupParticipants.swift; sourceTree = ""; }; + D0B843961DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangePeerNotificationSettings.swift; sourceTree = ""; }; + D0B843981DA7FF30005F29E1 /* NBAsYouTypeFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBAsYouTypeFormatter.m; sourceTree = ""; }; + D0B843991DA7FF30005F29E1 /* NBAsYouTypeFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBAsYouTypeFormatter.h; sourceTree = ""; }; + D0B8439A1DA7FF30005F29E1 /* NBMetadataCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBMetadataCore.h; sourceTree = ""; }; + D0B8439B1DA7FF30005F29E1 /* NBMetadataCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBMetadataCore.m; sourceTree = ""; }; + D0B8439C1DA7FF30005F29E1 /* NBMetadataCoreMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBMetadataCoreMapper.h; sourceTree = ""; }; + D0B8439D1DA7FF30005F29E1 /* NBMetadataCoreMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBMetadataCoreMapper.m; sourceTree = ""; }; + D0B8439E1DA7FF30005F29E1 /* NBMetadataCoreTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBMetadataCoreTest.h; sourceTree = ""; }; + D0B8439F1DA7FF30005F29E1 /* NBMetadataCoreTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBMetadataCoreTest.m; sourceTree = ""; }; + D0B843A01DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBMetadataCoreTestMapper.h; sourceTree = ""; }; + D0B843A11DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBMetadataCoreTestMapper.m; sourceTree = ""; }; + D0B843A21DA7FF30005F29E1 /* NBMetadataHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBMetadataHelper.h; sourceTree = ""; }; + D0B843A31DA7FF30005F29E1 /* NBMetadataHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBMetadataHelper.m; sourceTree = ""; }; + D0B843A41DA7FF30005F29E1 /* NBNumberFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBNumberFormat.h; sourceTree = ""; }; + D0B843A51DA7FF30005F29E1 /* NBNumberFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBNumberFormat.m; sourceTree = ""; }; + D0B843A61DA7FF30005F29E1 /* NBPhoneMetaData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneMetaData.h; sourceTree = ""; }; + D0B843A71DA7FF30005F29E1 /* NBPhoneMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneMetaData.m; sourceTree = ""; }; + D0B843A81DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneMetaDataGenerator.h; sourceTree = ""; }; + D0B843A91DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneMetaDataGenerator.m; sourceTree = ""; }; + D0B843AA1DA7FF30005F29E1 /* NBPhoneNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneNumber.h; sourceTree = ""; }; + D0B843AB1DA7FF30005F29E1 /* NBPhoneNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneNumber.m; sourceTree = ""; }; + D0B843AC1DA7FF30005F29E1 /* NBPhoneNumberDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneNumberDefines.h; sourceTree = ""; }; + D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneNumberDefines.m; sourceTree = ""; }; + D0B843AE1DA7FF30005F29E1 /* NBPhoneNumberDesc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneNumberDesc.h; sourceTree = ""; }; + D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneNumberDesc.m; sourceTree = ""; }; + D0B843B01DA7FF30005F29E1 /* NBPhoneNumberUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBPhoneNumberUtil.h; sourceTree = ""; }; + D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBPhoneNumberUtil.m; sourceTree = ""; }; + D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramUserPresence.swift; sourceTree = ""; }; + D0B85AC41F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentlyUsedHashtags.swift; sourceTree = ""; }; + D0BB7C591E5C8074001527C3 /* ChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelParticipants.swift; sourceTree = ""; }; + D0BC386D1E3FDAB70044D6FE /* CreateGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateGroup.swift; sourceTree = ""; }; + D0BC386F1E40853E0044D6FE /* UpdatePeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePeers.swift; sourceTree = ""; }; + D0BC38741E40A7F70044D6FE /* RemovePeerChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePeerChat.swift; sourceTree = ""; }; + D0BC38761E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizePinnedChatsOperations.swift; sourceTree = ""; }; + D0BC38781E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePinnedChatsOperation.swift; sourceTree = ""; }; + D0BC387A1E40D2880044D6FE /* TogglePeerChatPinned.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TogglePeerChatPinned.swift; sourceTree = ""; }; + D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdForm.swift; sourceTree = ""; }; + D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestSecureIdForm.swift; sourceTree = ""; }; + D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessSecureId.swift; sourceTree = ""; }; + D0BEAF5C1E54941B00BD963D /* Authorization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = ""; }; + D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; + D0C0B5891ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedLocalizationUpdatesOperations.swift; sourceTree = ""; }; + D0C0B58C1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeLocalizationUpdatesOperation.swift; sourceTree = ""; }; + D0C26D651FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeGroupedPeersOperation.swift; sourceTree = ""; }; + D0C26D681FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeGroupedPeersOperations.swift; sourceTree = ""; }; + D0C26D6B1FE286C3004ABF18 /* FetchChatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchChatList.swift; sourceTree = ""; }; + D0C27B3E1F4B51D000A4E170 /* CachedStickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedStickerPack.swift; sourceTree = ""; }; + D0C27B411F4B58C000A4E170 /* PeerSpecificStickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerSpecificStickerPack.swift; sourceTree = ""; }; + D0C44B601FC616E200227BE0 /* SearchGroupMembers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchGroupMembers.swift; sourceTree = ""; }; + D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArchivedStickerPacksInfo.swift; sourceTree = ""; }; + D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadedPeerFromMessage.swift; sourceTree = ""; }; + D0C50E331E93A86600F62E39 /* CallSessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallSessionManager.swift; sourceTree = ""; }; + D0CA3F83207391560042D2B6 /* SecureIdPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPadding.swift; sourceTree = ""; }; + D0CA8E4A227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeGroupMessageStats.swift; sourceTree = ""; }; + D0CAF2E91D75EC600011F558 /* MtProtoKitDynamic.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MtProtoKitDynamic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSortOrderAttribute.swift; sourceTree = ""; }; + D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerPackInteractiveOperations.swift; sourceTree = ""; }; + D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPendingPeerNotificationSettings.swift; sourceTree = ""; }; + D0DB7F021F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstallInteractiveReadMessagesAction.swift; sourceTree = ""; }; + D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestChatContextResults.swift; sourceTree = ""; }; + D0DC354F1DE36900000195EB /* ChatContextResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatContextResult.swift; sourceTree = ""; }; + D0DF0C891D819C7E008AEB01 /* JoinChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JoinChannel.swift; sourceTree = ""; }; + D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRepresentationsUtils.swift; sourceTree = ""; }; + D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageUtils.swift; sourceTree = ""; }; + D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerParticipants.swift; sourceTree = ""; }; + D0DFD5DE1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedSentMediaReferences.swift; sourceTree = ""; }; + D0E23DD41E8042F500B9B6D2 /* FeaturedStickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeaturedStickerPack.swift; sourceTree = ""; }; + D0E23DD91E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift; sourceTree = ""; }; + D0E23DDE1E8082A400B9B6D2 /* ArchivedStickerPacks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArchivedStickerPacks.swift; sourceTree = ""; }; + D0E305A61E5B5CBE00D7A3A2 /* PeerAdmins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerAdmins.swift; sourceTree = ""; }; + D0E305A91E5BA02D00D7A3A2 /* ChannelBlacklist.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelBlacklist.swift; sourceTree = ""; }; + D0E35A0D1DE4953E00BC6096 /* FetchHttpResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchHttpResource.swift; sourceTree = ""; }; + D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingMessageWithChatContextResult.swift; sourceTree = ""; }; + D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingChatContextResultMessageAttribute.swift; sourceTree = ""; }; + D0E412D6206A866B00BEE4A2 /* UploadSecureIdFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadSecureIdFile.swift; sourceTree = ""; }; + D0E412DB206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdValueAccessContext.swift; sourceTree = ""; }; + D0E412E0206AB24700BEE4A2 /* SecureFileMediaResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureFileMediaResource.swift; sourceTree = ""; }; + D0E412E6206ABC7500BEE4A2 /* EncryptedMediaResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedMediaResource.swift; sourceTree = ""; }; + D0E412E9206AD18E00BEE4A2 /* DecryptedResourceData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecryptedResourceData.swift; sourceTree = ""; }; + D0E412ED206AF65500BEE4A2 /* GrantSecureIdAccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrantSecureIdAccess.swift; sourceTree = ""; }; + D0E412F0206B9BB700BEE4A2 /* SecureIdPassportValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPassportValue.swift; sourceTree = ""; }; + D0E412F3206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdVerificationDocumentReference.swift; sourceTree = ""; }; + D0E41300206B9E6E00BEE4A2 /* SecureIdAddressValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdAddressValue.swift; sourceTree = ""; }; + D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateAccountPeerName.swift; sourceTree = ""; }; + D0E68768207534C90064BDB2 /* Api0.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Api0.swift; sourceTree = ""; }; + D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelAdminEventLogContext.swift; sourceTree = ""; }; + D0E8B8B22044706300605593 /* ForwardGame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardGame.swift; sourceTree = ""; }; + D0EA188120D3D2B1001AEE19 /* RemoteStorageConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteStorageConfiguration.swift; sourceTree = ""; }; + D0EC55992101ED0800D1992C /* DeleteMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteMessages.swift; sourceTree = ""; }; + D0EE7FC020986BF400981319 /* SecureIdInternalPassportValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdInternalPassportValue.swift; sourceTree = ""; }; + D0EE7FC320986C5300981319 /* SecureIdPassportRegistrationValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPassportRegistrationValue.swift; sourceTree = ""; }; + D0EE7FC62098853100981319 /* SecureIdTemporaryRegistrationValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdTemporaryRegistrationValue.swift; sourceTree = ""; }; + D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedConfigurationUpdates.swift; sourceTree = ""; }; + D0F19F6520E6620D00EEC860 /* MultiplexedRequestManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiplexedRequestManager.swift; sourceTree = ""; }; + D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeChatInputStateOperation.swift; sourceTree = ""; }; + D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeChatInputStateOperations.swift; sourceTree = ""; }; + D0F3A8A41E82C94C00B4C64C /* SynchronizeableChatInputState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeableChatInputState.swift; sourceTree = ""; }; + D0F3A8A71E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePeerChatInterfaceState.swift; sourceTree = ""; }; + D0F3CC7C1DDE289E008148FA /* ResolvePeerByName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResolvePeerByName.swift; sourceTree = ""; }; + D0F53BE81E784A4800117362 /* ChangeAccountPhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAccountPhoneNumber.swift; sourceTree = ""; }; + D0F760D722202FE20074F7E5 /* ChannelStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelStats.swift; sourceTree = ""; }; + D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditedMessageAttribute.swift; sourceTree = ""; }; + D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyMarkupMessageAttribute.swift; sourceTree = ""; }; + D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupFeedPeers.swift; sourceTree = ""; }; + D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalTelegramCoreConfiguration.swift; sourceTree = ""; }; + D0FA08BA2046B37900DD23FC /* ContentPrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPrivacySettings.swift; sourceTree = ""; }; + D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoStepVerification.swift; sourceTree = ""; }; + D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheStorageSettings.swift; sourceTree = ""; }; + D0FA35071EA632E400E56FFA /* CollectCacheUsageStats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectCacheUsageStats.swift; sourceTree = ""; }; + D0FA8B971E1E955C001E855B /* SecretChatOutgoingOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatOutgoingOperation.swift; sourceTree = ""; }; + D0FA8B9D1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatIncomingEncryptedOperation.swift; sourceTree = ""; }; + D0FA8BA01E1F99E1001E855B /* SecretChatFileReference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatFileReference.swift; sourceTree = ""; }; + D0FA8BA31E1FA341001E855B /* SecretChatKeychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatKeychain.swift; sourceTree = ""; }; + D0FA8BA61E1FA6DF001E855B /* TelegramSecretChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramSecretChat.swift; sourceTree = ""; }; + D0FA8BA91E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSecretChatOutgoingOperations.swift; sourceTree = ""; }; + D0FA8BAC1E1FD6E2001E855B /* MemoryBufferExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoryBufferExtensions.swift; sourceTree = ""; }; + D0FA8BAF1E1FEC7E001E855B /* SecretChatEncryptionConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatEncryptionConfig.swift; sourceTree = ""; }; + D0FA8BB21E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcessSecretChatIncomingEncryptedOperations.swift; sourceTree = ""; }; + D0FA8BB51E223C16001E855B /* SecretApiLayer8.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer8.swift; sourceTree = ""; }; + D0FA8BB81E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatIncomingDecryptedOperation.swift; sourceTree = ""; }; + D0FC195A2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerGroupMessageStateVersionAttribute.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D09D8BFD1D4FAB1D0081DBEC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0AF32381FAE8C920097362B /* MultipeerConnectivity.framework in Frameworks */, + D0CAF2EA1D75EC600011F558 /* MtProtoKitDynamic.framework in Frameworks */, + D067066C1D512ADB00DED3E3 /* Postbox.framework in Frameworks */, + D067066D1D512ADB00DED3E3 /* SwiftSignalKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D09D8C071D4FAB1D0081DBEC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D09D8C0B1D4FAB1D0081DBEC /* TelegramCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B418631D7E03D5004562A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0B4187F1D7E054E004562A4 /* MtProtoKitMac.framework in Frameworks */, + D0B418721D7E0409004562A4 /* PostboxMac.framework in Frameworks */, + D0B418731D7E0409004562A4 /* SwiftSignalKitMac.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D01B27A01E394D7B0022A4C0 /* Settings */ = { + isa = PBXGroup; + children = ( + 0900555521E4A96D0030924C /* Wallpaper.swift */, + D01B27A11E394D8B0022A4C0 /* PrivacySettings.swift */, + D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */, + D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */, + D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */, + D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */, + D01C7ED21EF5DF83008305F1 /* LimitsConfiguration.swift */, + D0A3E446214802C7008ACEF6 /* VoipConfiguration.swift */, + D0EA188120D3D2B1001AEE19 /* RemoteStorageConfiguration.swift */, + D01C7ED51EF5E468008305F1 /* ProxySettings.swift */, + D04D8FF3209A4B0700865719 /* NetworkSettings.swift */, + D0B167221F9F972E00976B40 /* LoggingSettings.swift */, + D0AF32301FACEDEC0097362B /* CoreSettings.swift */, + D0FA08BA2046B37900DD23FC /* ContentPrivacySettings.swift */, + D051DB13215EC5A300F30F92 /* AppChangelogState.swift */, + 0962E66E21B6147600245FD9 /* AppConfiguration.swift */, + 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */, + 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */, + ); + name = Settings; + sourceTree = ""; + }; + D021E0DD1DB539E800C6B04F /* Item Collections */ = { + isa = PBXGroup; + children = ( + D021E0DE1DB539FC00C6B04F /* StickerPack.swift */, + D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */, + D01A21AB1F38D10E00DDA104 /* SavedStickerItem.swift */, + D049EAE71E44B67100A2CD3A /* RecentPeerItem.swift */, + D0E23DD41E8042F500B9B6D2 /* FeaturedStickerPack.swift */, + D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */, + ); + name = "Item Collections"; + sourceTree = ""; + }; + D021E0E01DB5400200C6B04F /* Sticker Management */ = { + isa = PBXGroup; + children = ( + D021E0E11DB5401A00C6B04F /* StickerManagement.swift */, + D01D6BF81E42A713006151C6 /* SearchStickers.swift */, + D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */, + C251D7421E65E50500283EDE /* StickerSetInstallation.swift */, + D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */, + D05452061E7B5093006EEF19 /* LoadedStickerPack.swift */, + D0E23DDE1E8082A400B9B6D2 /* ArchivedStickerPacks.swift */, + D0C27B3E1F4B51D000A4E170 /* CachedStickerPack.swift */, + D0C27B411F4B58C000A4E170 /* PeerSpecificStickerPack.swift */, + C29340F21F5080FA0074991E /* UpdateGroupSpecificStickerset.swift */, + ); + name = "Sticker Management"; + sourceTree = ""; + }; + D03B0C791D62153400955575 /* third-party */ = { + isa = PBXGroup; + children = ( + D03B0C7A1D6222CA00955575 /* libphonenumber-iOS */, + ); + name = "third-party"; + sourceTree = ""; + }; + D03B0C7A1D6222CA00955575 /* libphonenumber-iOS */ = { + isa = PBXGroup; + children = ( + D0B843981DA7FF30005F29E1 /* NBAsYouTypeFormatter.m */, + D0B843991DA7FF30005F29E1 /* NBAsYouTypeFormatter.h */, + D0B8439A1DA7FF30005F29E1 /* NBMetadataCore.h */, + D0B8439B1DA7FF30005F29E1 /* NBMetadataCore.m */, + D0B8439C1DA7FF30005F29E1 /* NBMetadataCoreMapper.h */, + D0B8439D1DA7FF30005F29E1 /* NBMetadataCoreMapper.m */, + D0B8439E1DA7FF30005F29E1 /* NBMetadataCoreTest.h */, + D0B8439F1DA7FF30005F29E1 /* NBMetadataCoreTest.m */, + D0B843A01DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h */, + D0B843A11DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m */, + D0B843A21DA7FF30005F29E1 /* NBMetadataHelper.h */, + D0B843A31DA7FF30005F29E1 /* NBMetadataHelper.m */, + D0B843A41DA7FF30005F29E1 /* NBNumberFormat.h */, + D0B843A51DA7FF30005F29E1 /* NBNumberFormat.m */, + D0B843A61DA7FF30005F29E1 /* NBPhoneMetaData.h */, + D0B843A71DA7FF30005F29E1 /* NBPhoneMetaData.m */, + D0B843A81DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h */, + D0B843A91DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m */, + D0B843AA1DA7FF30005F29E1 /* NBPhoneNumber.h */, + D0B843AB1DA7FF30005F29E1 /* NBPhoneNumber.m */, + D0B843AC1DA7FF30005F29E1 /* NBPhoneNumberDefines.h */, + D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */, + D0B843AE1DA7FF30005F29E1 /* NBPhoneNumberDesc.h */, + D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */, + D0B843B01DA7FF30005F29E1 /* NBPhoneNumberUtil.h */, + D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */, + ); + name = "libphonenumber-iOS"; + path = "third-party/libphonenumber-iOS"; + sourceTree = SOURCE_ROOT; + }; + D03B0CB71D62232000955575 /* Utils */ = { + isa = PBXGroup; + children = ( + D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */, + D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */, + D03B0CB81D62233400955575 /* Either.swift */, + D03B0CBC1D62234300955575 /* Regex.swift */, + D03B0CBE1D62234A00955575 /* Log.swift */, + D03B0CC01D62235000955575 /* StringFormat.swift */, + D03B0CCD1D62239600955575 /* PhoneNumbers.swift */, + D0FA8BAC1E1FD6E2001E855B /* MemoryBufferExtensions.swift */, + D0448C9E1E27F5EB005A61A7 /* Random.swift */, + D050F20F1E48AB0600988324 /* InteractivePhoneFormatter.swift */, + D04CAA591E83310D0047E51F /* MD5.swift */, + D042C6821E8D9DF800C863B0 /* Unixtime.swift */, + D01C7F031EFC1C49008305F1 /* DeviceContact.swift */, + D053B3FD1F16534400E2D58A /* MonotonicTime.swift */, + D01C06B61FBBA269001561AB /* CanSendMessagesToPeer.swift */, + D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */, + D0E412E9206AD18E00BEE4A2 /* DecryptedResourceData.swift */, + C28D3CEF20D3DA900027F4D6 /* DeepLinkInfo.swift */, + 0962E66C21B5C56F00245FD9 /* JSON.swift */, + 0962E67421B6437600245FD9 /* SplitTest.swift */, + ); + name = Utils; + sourceTree = ""; + }; + D03B0CCF1D62242200955575 /* Objects */ = { + isa = PBXGroup; + children = ( + D03B0CD21D62244300955575 /* Namespaces.swift */, + D03E5E0A1E55E0220029569A /* Accounts */, + D03B0CD01D62242C00955575 /* Peers */, + D03B0CD11D62242F00955575 /* Messages */, + D0FA8B961E1E952D001E855B /* Secret Chats */, + D021E0DD1DB539E800C6B04F /* Item Collections */, + D01B27A01E394D7B0022A4C0 /* Settings */, + D08CAA821ED816290000FDA8 /* Localization */, + ); + name = Objects; + sourceTree = ""; + }; + D03B0CD01D62242C00955575 /* Peers */ = { + isa = PBXGroup; + children = ( + D03B0CDA1D62245F00955575 /* ApiUtils.swift */, + D03B0CD81D62245B00955575 /* PeerUtils.swift */, + D09A2FEA1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift */, + D03B0CD41D62245300955575 /* TelegramUser.swift */, + D03B0CD51D62245300955575 /* TelegramGroup.swift */, + D09A2FE51D7CD4940018FB72 /* TelegramChannel.swift */, + D0FA8BA61E1FA6DF001E855B /* TelegramSecretChat.swift */, + D0B417C01D7DCEEF004562A4 /* ApiGroupOrChannel.swift */, + D003702A1DA42586004308D3 /* PhoneNumber.swift */, + D0B8438B1DA7CF50005F29E1 /* BotInfo.swift */, + D0B843881DA7AB96005F29E1 /* ExportedInvitation.swift */, + D0B8438D1DA7D296005F29E1 /* CachedGroupParticipants.swift */, + D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */, + D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */, + D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */, + D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */, + D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */, + D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */, + D033FEAF1E61EB0200644997 /* PeerContactSettings.swift */, + D0F3A8A41E82C94C00B4C64C /* SynchronizeableChatInputState.swift */, + D00BDA181EE593D600C64C5E /* TelegramChannelAdminRights.swift */, + D00BDA1B1EE5952A00C64C5E /* TelegramChannelBannedRights.swift */, + ); + name = Peers; + sourceTree = ""; + }; + D03B0CD11D62242F00955575 /* Messages */ = { + isa = PBXGroup; + children = ( + D03B0CDF1D62249100955575 /* StoreMessage_Telegram.swift */, + D03B0CDC1D62247800955575 /* Attributes */, + D03B0CDD1D62247D00955575 /* Media */, + ); + name = Messages; + sourceTree = ""; + }; + D03B0CDC1D62247800955575 /* Attributes */ = { + isa = PBXGroup; + children = ( + D0AAD1A71E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift */, + D03B0CE71D6224AD00955575 /* ViewCountMessageAttribute.swift */, + D03B0CE51D6224A700955575 /* ReplyMessageAttribute.swift */, + D03B0CE31D62249F00955575 /* TextEntitiesMessageAttribute.swift */, + D03B0CE11D62249B00955575 /* InlineBotMessageAttribute.swift */, + D053B4171F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift */, + D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */, + D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */, + D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */, + D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */, + D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */, + D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */, + D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */, + D07047B31F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift */, + D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */, + D0FC195A2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift */, + C28725411EF967E700613564 /* NotificationInfoMessageAttribute.swift */, + C210DD611FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift */, + D0439B5F228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift */, + ); + name = Attributes; + sourceTree = ""; + }; + D03B0CDD1D62247D00955575 /* Media */ = { + isa = PBXGroup; + children = ( + D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */, + D03B0CEC1D62250800955575 /* TelegramMediaAction.swift */, + D03B0CED1D62250800955575 /* TelegramMediaContact.swift */, + D03B0CEE1D62250800955575 /* TelegramMediaFile.swift */, + D03B0CEF1D62250800955575 /* TelegramMediaImage.swift */, + D03B0CF11D62250800955575 /* TelegramMediaMap.swift */, + D03B0CF31D62250800955575 /* TelegramMediaWebpage.swift */, + D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */, + D053B41A1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift */, + D07827CA1E02F5B200071108 /* RichText.swift */, + D07827C81E02F59C00071108 /* InstantPage.swift */, + C2E064671ECEEF0A00387BB8 /* TelegramMediaInvoice.swift */, + C2E0646C1ECF171D00387BB8 /* TelegramMediaWebDocument.swift */, + D0AB262521C2F991008F6685 /* TelegramMediaPoll.swift */, + ); + name = Media; + sourceTree = ""; + }; + D03B0CFE1D62252200955575 /* State */ = { + isa = PBXGroup; + children = ( + D03B0CFF1D62255C00955575 /* ChannelState.swift */, + D03DC9121F82F89D001D584C /* RegularChatState.swift */, + D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */, + D03B0D001D62255C00955575 /* EnqueueMessage.swift */, + D03B0D011D62255C00955575 /* Holes.swift */, + D017495D1E118F790057C89A /* AccountStateManager.swift */, + D017495F1E118FC30057C89A /* AccountIntermediateState.swift */, + D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */, + D03B0D051D62255C00955575 /* UpdateGroup.swift */, + D03DC90F1F82E344001D584C /* AccountStateReset.swift */, + D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */, + D03B0D061D62255C00955575 /* UpdateMessageService.swift */, + D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */, + D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */, + D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */, + D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */, + D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */, + D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */, + D0AAD1B71E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift */, + D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */, + D0AB0B991D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift */, + D0BC38781E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift */, + D0BC38761E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift */, + D00DBBD91E64E67E00DB5485 /* UpdateSecretChat.swift */, + D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */, + D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */, + D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */, + D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */, + D0E23DD91E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift */, + D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */, + D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */, + D0575AF01E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift */, + D0575AF31E9FFDDD006F2541 /* ManagedSynchronizeSavedGifsOperations.swift */, + D01A21A51F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift */, + D01A21A81F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift */, + D058E0D01E8AD65C00A442DE /* StandaloneSendMessage.swift */, + D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */, + D0C0B58C1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift */, + D0C0B5891ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift */, + D07047B91F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift */, + D07047B61F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift */, + D0C26D651FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift */, + D0C26D681FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift */, + D0AF32211FAC95C20097362B /* StandaloneUploadedMedia.swift */, + D0380DB9204EF306000414AB /* MessageMediaPreuploadManager.swift */, + D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */, + D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */, + D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */, + D00422D221677F4500719B67 /* ManagedAccountPresence.swift */, + D0A8998E217A37A000759EE6 /* NotificationAutolockReportManager.swift */, + 09028385218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift */, + D0529D2321A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift */, + D0529D2621A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift */, + 0962E66621B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift */, + 0962E66821B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift */, + 0962E66A21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift */, + 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */, + 093857A72243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift */, + 093857A62243D87800EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift */, + D0CA8E4A227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift */, + D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */, + ); + name = State; + sourceTree = ""; + }; + D03B0D111D62256B00955575 /* Media */ = { + isa = PBXGroup; + children = ( + D03B0D121D62257600955575 /* Resources */, + D0DFD5DE1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift */, + ); + name = Media; + sourceTree = ""; + }; + D03B0D121D62257600955575 /* Resources */ = { + isa = PBXGroup; + children = ( + D032F5BB20EF84FD00037B6C /* FetchedMediaResource.swift */, + D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */, + D03B0D431D6319F900955575 /* CloudFileMediaResource.swift */, + D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */, + D03B0D391D6319E200955575 /* Fetch.swift */, + D0E35A0D1DE4953E00BC6096 /* FetchHttpResource.swift */, + D0448CA11E291B14005A61A7 /* FetchSecretFileResource.swift */, + D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */, + D0E412E6206ABC7500BEE4A2 /* EncryptedMediaResource.swift */, + D0E412E0206AB24700BEE4A2 /* SecureFileMediaResource.swift */, + D0633CDA2253C0D3003DD95F /* CloudMediaResourceParameters.swift */, + ); + name = Resources; + sourceTree = ""; + }; + D03B0D531D631A4400955575 /* Network */ = { + isa = PBXGroup; + children = ( + D09F9DC620767D2C00DB4DE1 /* Api1.swift */, + D09F9DC720767D2C00DB4DE1 /* Api2.swift */, + D09F9DC520767D2C00DB4DE1 /* Api3.swift */, + D0E68768207534C90064BDB2 /* Api0.swift */, + D0FA8BB51E223C16001E855B /* SecretApiLayer8.swift */, + D0448C981E268F9A005A61A7 /* SecretApiLayer46.swift */, + D018EDFF2044939F00CBB130 /* SecretApiLayer73.swift */, + D03B0D551D631A6900955575 /* Buffer.swift */, + D03B0D561D631A6900955575 /* Download.swift */, + D03B0D571D631A6900955575 /* MultipartFetch.swift */, + D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */, + D03B0D581D631A6900955575 /* Network.swift */, + D03B0D591D631A6900955575 /* Serialization.swift */, + D06AFE8820BF66BF00EA5124 /* DeserializeFunctionResponse.swift */, + D0F19F6520E6620D00EEC860 /* MultiplexedRequestManager.swift */, + D08984F421187ECA00918162 /* NetworkType.swift */, + ); + name = Network; + sourceTree = ""; + }; + D03B0D601D631A7200955575 /* Account */ = { + isa = PBXGroup; + children = ( + D03B0D611D631A8B00955575 /* Account.swift */, + D049EAF41E44DF3300A2CD3A /* AccountState.swift */, + D03B0D631D631A8B00955575 /* AccountViewTracker.swift */, + D03B0D641D631A8B00955575 /* RecentPeers.swift */, + D0AB0B911D65E9FA002C78E7 /* ManagedServiceViews.swift */, + D0AB0B931D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift */, + D0AB0B951D662F0B002C78E7 /* ManagedChatListHoles.swift */, + D0B843861DA6F705005F29E1 /* UpdateCachedPeerData.swift */, + D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */, + D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */, + D0BEAF5C1E54941B00BD963D /* Authorization.swift */, + D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */, + D0528E591E658B3600E2FEF5 /* ManagedLocalInputActivities.swift */, + D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */, + D0B1671C1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift */, + D06ECFC720B810D300C576C2 /* TermsOfService.swift */, + D051DB16215ECC4D00F30F92 /* AppChangelog.swift */, + D01843A72190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift */, + D02B198F21FB1D520094A764 /* RegisterNotificationToken.swift */, + D0338742223BD532007A2CE4 /* InitializeAccountAfterLogin.swift */, + ); + name = Account; + sourceTree = ""; + }; + D03B0D691D631A9200955575 /* Contacts */ = { + isa = PBXGroup; + children = ( + D03B0D6C1D631AA300955575 /* ContactManagement.swift */, + D0B2F7732052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift */, + D02DADC02139A1FC00116225 /* ContactSyncManager.swift */, + D0439B5C228ECB270067E026 /* RequestPhoneNumber.swift */, + ); + name = Contacts; + sourceTree = ""; + }; + D03B0D6E1D631AA900955575 /* Messages */ = { + isa = PBXGroup; + children = ( + D03B0D711D631ABA00955575 /* SearchMessages.swift */, + D0EC55992101ED0800D1992C /* DeleteMessages.swift */, + D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */, + D0AB262A21C3CE80008F6685 /* Polls.swift */, + D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */, + D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */, + D0DC354F1DE36900000195EB /* ChatContextResult.swift */, + D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */, + D01749581E1092BC0057C89A /* RequestStartBot.swift */, + D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */, + D0AAD1A91E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift */, + D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */, + C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */, + D0528E5F1E65B94E00E2FEF5 /* SingleMessageView.swift */, + D0528E691E65DD2100E2FEF5 /* WebpagePreview.swift */, + D0FA35071EA632E400E56FFA /* CollectCacheUsageStats.swift */, + D0642EF81F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift */, + D0DB7F021F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift */, + D0B85AC41F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift */, + D0E8B8B22044706300605593 /* ForwardGame.swift */, + D0119CAF20CA9EA800895300 /* MarkAllChatsAsRead.swift */, + D023E67721540624008C27D1 /* UpdateMessageMedia.swift */, + ); + name = Messages; + sourceTree = ""; + }; + D03B0E3A1D631E4400955575 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D03B0E5B1D63240700955575 /* TelegramCoreIncludes.h */, + D03B0E411D631E6600955575 /* NetworkLogging.h */, + D03B0E421D631E6600955575 /* NetworkLogging.m */, + D053B3F91F1651FA00E2D58A /* MonotonicTime.h */, + D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */, + D02609BB20C6EB97006C34AC /* Crypto.h */, + D02609BE20C6EC08006C34AC /* Crypto.m */, + D08984F72118816900918162 /* Reachability.h */, + D08984F82118816A00918162 /* Reachability.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D03E5E0A1E55E0220029569A /* Accounts */ = { + isa = PBXGroup; + children = ( + D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */, + D00580AD21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift */, + D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */, + ); + name = Accounts; + sourceTree = ""; + }; + D05A32DF1E6F096B002760B4 /* Settings */ = { + isa = PBXGroup; + children = ( + D026099D20C695AF006C34AC /* Wallpapers.swift */, + D05A32E01E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift */, + D05A32E31E6F0B2E002760B4 /* RecentAccountSessions.swift */, + D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */, + D0F53BE81E784A4800117362 /* ChangeAccountPhoneNumber.swift */, + 9FC8ADAA206BBFF10094F7B4 /* RecentWebSessions.swift */, + D07E413E208A769D00FCA8F0 /* ProxyServersStatuses.swift */, + D08984F12114B97400918162 /* ClearCloudDrafts.swift */, + D04554A521B43440007A6DD9 /* CancelAccountReset.swift */, + D033873F223BD48B007A2CE4 /* ContactsSettings.swift */, + D099E221229420D600561B75 /* BlockedPeersContext.swift */, + D098907E22942E3B0053F151 /* ActiveSessionsContext.swift */, + ); + name = Settings; + sourceTree = ""; + }; + D06706631D512ADA00DED3E3 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D0AF32371FAE8C910097362B /* MultipeerConnectivity.framework */, + D0B4187E1D7E054E004562A4 /* MtProtoKitMac.framework */, + D0B418701D7E0409004562A4 /* PostboxMac.framework */, + D0B418711D7E0409004562A4 /* SwiftSignalKitMac.framework */, + D0CAF2E91D75EC600011F558 /* MtProtoKitDynamic.framework */, + D0AC49491D7097A400AA55DA /* SSignalKit.framework */, + D03B0E6B1D63283C00955575 /* libiconv.tbd */, + D03B0E691D63283000955575 /* libwebp.a */, + D03B0E611D63281A00955575 /* libavcodec.a */, + D03B0E621D63281A00955575 /* libavformat.a */, + D03B0E631D63281A00955575 /* libavutil.a */, + D03B0E641D63281A00955575 /* libswresample.a */, + D03B0E5F1D6327FF00955575 /* libz.tbd */, + D03B0E5D1D6327F600955575 /* SSignalKit.framework */, + D03B0E571D631EB900955575 /* CoreMedia.framework */, + D067066E1D512AEB00DED3E3 /* MtProtoKit.framework */, + D06706641D512ADB00DED3E3 /* AsyncDisplayKit.framework */, + D06706651D512ADB00DED3E3 /* Display.framework */, + D06706671D512ADB00DED3E3 /* Postbox.framework */, + D06706681D512ADB00DED3E3 /* SwiftSignalKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + D0754D281EEE10D800884F6E /* Bot Payments */ = { + isa = PBXGroup; + children = ( + D0754D291EEE10FC00884F6E /* BotPaymentForm.swift */, + ); + name = "Bot Payments"; + sourceTree = ""; + }; + D08CAA821ED816290000FDA8 /* Localization */ = { + isa = PBXGroup; + children = ( + D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */, + D08CAA831ED8164B0000FDA8 /* Localization.swift */, + D08CAA861ED81DD40000FDA8 /* LocalizationInfo.swift */, + D05D8B362192F8AF0064586F /* LocalizationListState.swift */, + 093857AA2243D88C00EB6A54 /* EmojiKeywords.swift */, + ); + name = Localization; + sourceTree = ""; + }; + D08CAA8A1ED81EA10000FDA8 /* Localization */ = { + isa = PBXGroup; + children = ( + D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */, + D081E109217F5ADE003CD921 /* LocalizationPreview.swift */, + ); + name = Localization; + sourceTree = ""; + }; + D093D7E82064135300BC3599 /* Values */ = { + isa = PBXGroup; + children = ( + D02D60A6206BA5F900FEFE1E /* SecureIdValue.swift */, + D0E412DB206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift */, + D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */, + D0E412F3206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift */, + D054648A2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift */, + D0EE7FC020986BF400981319 /* SecureIdInternalPassportValue.swift */, + D0E412F0206B9BB700BEE4A2 /* SecureIdPassportValue.swift */, + D054648D20738626002ECC1E /* SecureIdDriversLicenseValue.swift */, + D054649020738653002ECC1E /* SecureIdIDCardValue.swift */, + D0E41300206B9E6E00BEE4A2 /* SecureIdAddressValue.swift */, + D0546493207386D7002ECC1E /* SecureIdUtilityBillValue.swift */, + D05464962073872C002ECC1E /* SecureIdBankStatementValue.swift */, + D054649920738760002ECC1E /* SecureIdRentalAgreementValue.swift */, + D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */, + D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */, + D0EE7FC320986C5300981319 /* SecureIdPassportRegistrationValue.swift */, + D0EE7FC62098853100981319 /* SecureIdTemporaryRegistrationValue.swift */, + ); + name = Values; + sourceTree = ""; + }; + D09D8BF71D4FAB1D0081DBEC = { + isa = PBXGroup; + children = ( + D03B0E591D63215200955575 /* TelegramCore.xcconfig */, + D09D8C031D4FAB1D0081DBEC /* TelegramCore */, + D09D8C0E1D4FAB1D0081DBEC /* TelegramCoreTests */, + D0B418681D7E03D5004562A4 /* TelegramCoreMac */, + D09D8C021D4FAB1D0081DBEC /* Products */, + D06706631D512ADA00DED3E3 /* Frameworks */, + ); + sourceTree = ""; + }; + D09D8C021D4FAB1D0081DBEC /* Products */ = { + isa = PBXGroup; + children = ( + D09D8C011D4FAB1D0081DBEC /* TelegramCore.framework */, + D09D8C0A1D4FAB1D0081DBEC /* TelegramCoreTests.xctest */, + D0B418671D7E03D5004562A4 /* TelegramCoreMac.framework */, + ); + name = Products; + sourceTree = ""; + }; + D09D8C031D4FAB1D0081DBEC /* TelegramCore */ = { + isa = PBXGroup; + children = ( + D03B0C791D62153400955575 /* third-party */, + D03B0CB71D62232000955575 /* Utils */, + D03B0CCF1D62242200955575 /* Objects */, + D03B0CFE1D62252200955575 /* State */, + D03B0D111D62256B00955575 /* Media */, + D03B0D531D631A4400955575 /* Network */, + D03B0D601D631A7200955575 /* Account */, + D03B0D691D631A9200955575 /* Contacts */, + D03B0D6E1D631AA900955575 /* Messages */, + D0DF0C881D819C5F008AEB01 /* Peers */, + D0754D281EEE10D800884F6E /* Bot Payments */, + D0BE303820619E9E00FBE6D8 /* Secure ID */, + D0C50E2F1E93A83B00F62E39 /* Calls */, + D021E0E01DB5400200C6B04F /* Sticker Management */, + D05A32DF1E6F096B002760B4 /* Settings */, + D08CAA8A1ED81EA10000FDA8 /* Localization */, + D0AD02E61FFFA15C00C1DCFF /* Live Location */, + D0AF32331FAE8C540097362B /* Multipeer */, + D03B0E3A1D631E4400955575 /* Supporting Files */, + D09D8C041D4FAB1D0081DBEC /* TelegramCore.h */, + D09D8C051D4FAB1D0081DBEC /* Info.plist */, + ); + path = TelegramCore; + sourceTree = ""; + }; + D09D8C0E1D4FAB1D0081DBEC /* TelegramCoreTests */ = { + isa = PBXGroup; + children = ( + D09D8C0F1D4FAB1D0081DBEC /* TelegramCoreTests.m */, + D09D8C111D4FAB1D0081DBEC /* Info.plist */, + ); + path = TelegramCoreTests; + sourceTree = ""; + }; + D0AD02E61FFFA15C00C1DCFF /* Live Location */ = { + isa = PBXGroup; + children = ( + D0AD02E21FFFA14800C1DCFF /* PeerLiveLocationsContext.swift */, + ); + name = "Live Location"; + sourceTree = ""; + }; + D0AF32331FAE8C540097362B /* Multipeer */ = { + isa = PBXGroup; + children = ( + D0AF32341FAE8C6B0097362B /* MultipeerManager.swift */, + ); + name = Multipeer; + sourceTree = ""; + }; + D0B418681D7E03D5004562A4 /* TelegramCoreMac */ = { + isa = PBXGroup; + children = ( + D0B418691D7E03D5004562A4 /* TelegramCoreMac.h */, + D0B4186A1D7E03D5004562A4 /* Info.plist */, + ); + path = TelegramCoreMac; + sourceTree = ""; + }; + D0BE303820619E9E00FBE6D8 /* Secure ID */ = { + isa = PBXGroup; + children = ( + D0CA3F82207391450042D2B6 /* Utils */, + D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */, + D0ADF910212B00DD00310BBC /* SecureIdConfiguration.swift */, + D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */, + D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */, + D093D805206539D000BC3599 /* SaveSecureIdValue.swift */, + D0E412D6206A866B00BEE4A2 /* UploadSecureIdFile.swift */, + D0E412ED206AF65500BEE4A2 /* GrantSecureIdAccess.swift */, + D02D60AA206BA64100FEFE1E /* VerifySecureIdValue.swift */, + D0136308208F3B0900EB3653 /* SecureIdValueContentError.swift */, + D093D7E82064135300BC3599 /* Values */, + ); + name = "Secure ID"; + sourceTree = ""; + }; + D0C50E2F1E93A83B00F62E39 /* Calls */ = { + isa = PBXGroup; + children = ( + D0C50E331E93A86600F62E39 /* CallSessionManager.swift */, + C2F4ED1C1EC60064005F2696 /* RateCall.swift */, + ); + name = Calls; + sourceTree = ""; + }; + D0CA3F82207391450042D2B6 /* Utils */ = { + isa = PBXGroup; + children = ( + D0CA3F83207391560042D2B6 /* SecureIdPadding.swift */, + ); + name = Utils; + sourceTree = ""; + }; + D0DF0C881D819C5F008AEB01 /* Peers */ = { + isa = PBXGroup; + children = ( + D0C26D6B1FE286C3004ABF18 /* FetchChatList.swift */, + D0BC386F1E40853E0044D6FE /* UpdatePeers.swift */, + D0DF0C891D819C7E008AEB01 /* JoinChannel.swift */, + D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */, + D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */, + D0B843961DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift */, + D0F3CC7C1DDE289E008148FA /* ResolvePeerByName.swift */, + D07827BA1E00451F00071108 /* SearchPeers.swift */, + D0BC386D1E3FDAB70044D6FE /* CreateGroup.swift */, + D018D3361E648ACF00C5E089 /* ChannelCreation.swift */, + D00DBBD61E64E41100DB5485 /* CreateSecretChat.swift */, + D0BC38741E40A7F70044D6FE /* RemovePeerChat.swift */, + D0BC387A1E40D2880044D6FE /* TogglePeerChatPinned.swift */, + D049EAEA1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift */, + D050F2501E4A59C200988324 /* JoinLink.swift */, + C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */, + C2366C851E4F403C0097CCFF /* AddressNames.swift */, + D0613FC91E60440600202CDB /* InvitationLinks.swift */, + C2366C881E4F40480097CCFF /* SupportPeerId.swift */, + D0BB7C591E5C8074001527C3 /* ChannelParticipants.swift */, + D041E3F41E535464008C24B4 /* AddPeerMember.swift */, + D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */, + D0561DE21E5737FC00E6B9E9 /* UpdatePeerInfo.swift */, + D0561DE91E5754FA00E6B9E9 /* ChannelAdmins.swift */, + D0613FCE1E60520700202CDB /* ChannelMembers.swift */, + D0E305A91E5BA02D00D7A3A2 /* ChannelBlacklist.swift */, + D0E305A61E5B5CBE00D7A3A2 /* PeerAdmins.swift */, + D0613FD61E606B3B00202CDB /* ConvertGroupToSupergroup.swift */, + D033FEB21E61F3C000644997 /* ReportPeer.swift */, + D033FEB51E61F3F900644997 /* BlockedPeers.swift */, + C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */, + D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */, + C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */, + C2FD33E01E680E9E008D13D4 /* RequestUserPhotos.swift */, + C2FD33E31E687BF1008D13D4 /* PeerPhotoUpdater.swift */, + C2FD33EA1E696C78008D13D4 /* GroupsInCommon.swift */, + D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */, + D0F3A8A71E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift */, + C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */, + C205FEA71EB3B75900455808 /* ExportMessageLink.swift */, + C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */, + D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */, + D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */, + D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */, + D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */, + D0C44B601FC616E200227BE0 /* SearchGroupMembers.swift */, + D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */, + D018EE042045E95000CBB130 /* CheckPeerChatServiceActions.swift */, + 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */, + D0F760D722202FE20074F7E5 /* ChannelStats.swift */, + D0633CD12253A528003DD95F /* ChatOnlineMembers.swift */, + D015E00D225CA61100CB9E8A /* FindChannelById.swift */, + D076F8882296D8E9004F895A /* ManageChannelDiscussionGroup.swift */, + 090E778222A9862100CD99F5 /* ChannelOwnershipTransfer.swift */, + 090E778F22AAABC600CD99F5 /* PeersNearby.swift */, + ); + name = Peers; + sourceTree = ""; + }; + D0FA8B961E1E952D001E855B /* Secret Chats */ = { + isa = PBXGroup; + children = ( + D0FA8BA31E1FA341001E855B /* SecretChatKeychain.swift */, + D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */, + D0FA8BAF1E1FEC7E001E855B /* SecretChatEncryptionConfig.swift */, + D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */, + D0FA8B9D1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift */, + D0FA8BB81E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift */, + D0FA8B971E1E955C001E855B /* SecretChatOutgoingOperation.swift */, + D0FA8BA01E1F99E1001E855B /* SecretChatFileReference.swift */, + D0FA8BB21E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift */, + D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */, + D0FA8BA91E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift */, + D019B1CB1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift */, + D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */, + D018EE0120458E1E00CBB130 /* SecretChatLayerNegotiation.swift */, + ); + name = "Secret Chats"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D09D8BFE1D4FAB1D0081DBEC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0B843C01DA7FF30005F29E1 /* NBPhoneMetaData.h in Headers */, + D03B0E431D631E6600955575 /* NetworkLogging.h in Headers */, + D0B843B81DA7FF30005F29E1 /* NBMetadataCoreTest.h in Headers */, + D09D8C121D4FAB1D0081DBEC /* TelegramCore.h in Headers */, + D03B0E5C1D63241D00955575 /* TelegramCoreIncludes.h in Headers */, + D0B843B61DA7FF30005F29E1 /* NBMetadataCoreMapper.h in Headers */, + D0B843B41DA7FF30005F29E1 /* NBMetadataCore.h in Headers */, + D0B843C41DA7FF30005F29E1 /* NBPhoneNumber.h in Headers */, + D0B843B31DA7FF30005F29E1 /* NBAsYouTypeFormatter.h in Headers */, + D08984F92118816A00918162 /* Reachability.h in Headers */, + D053B3FB1F1651FA00E2D58A /* MonotonicTime.h in Headers */, + D0B843C81DA7FF30005F29E1 /* NBPhoneNumberDesc.h in Headers */, + D0B843CA1DA7FF30005F29E1 /* NBPhoneNumberUtil.h in Headers */, + D0B843BA1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.h in Headers */, + D0B843BE1DA7FF30005F29E1 /* NBNumberFormat.h in Headers */, + D0B843C61DA7FF30005F29E1 /* NBPhoneNumberDefines.h in Headers */, + D0B843C21DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.h in Headers */, + D0B843BC1DA7FF30005F29E1 /* NBMetadataHelper.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B418641D7E03D5004562A4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D050F25A1E4A5AC500988324 /* NBPhoneMetaData.h in Headers */, + D0B4186B1D7E03D5004562A4 /* TelegramCoreMac.h in Headers */, + D050F2561E4A5AC500988324 /* NBMetadataCoreTest.h in Headers */, + D0B418BC1D7E05D0004562A4 /* TelegramCoreIncludes.h in Headers */, + D0B418BB1D7E05BE004562A4 /* NetworkLogging.h in Headers */, + D050F2551E4A5AC500988324 /* NBMetadataCoreMapper.h in Headers */, + D050F2541E4A5AC500988324 /* NBMetadataCore.h in Headers */, + D050F25C1E4A5AC500988324 /* NBPhoneNumber.h in Headers */, + D050F2531E4A5AC500988324 /* NBAsYouTypeFormatter.h in Headers */, + D050F25E1E4A5AC500988324 /* NBPhoneNumberDesc.h in Headers */, + D050F25F1E4A5AC500988324 /* NBPhoneNumberUtil.h in Headers */, + D050F2571E4A5AC500988324 /* NBMetadataCoreTestMapper.h in Headers */, + D050F2591E4A5AC500988324 /* NBNumberFormat.h in Headers */, + D050F25D1E4A5AC500988324 /* NBPhoneNumberDefines.h in Headers */, + D08984FA2118816A00918162 /* Reachability.h in Headers */, + D050F25B1E4A5AC500988324 /* NBPhoneMetaDataGenerator.h in Headers */, + D050F2581E4A5AC500988324 /* NBMetadataHelper.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D09D8C001D4FAB1D0081DBEC /* TelegramCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = D09D8C151D4FAB1D0081DBEC /* Build configuration list for PBXNativeTarget "TelegramCore" */; + buildPhases = ( + D09D8BFC1D4FAB1D0081DBEC /* Sources */, + D09D8BFD1D4FAB1D0081DBEC /* Frameworks */, + D09D8BFE1D4FAB1D0081DBEC /* Headers */, + D09D8BFF1D4FAB1D0081DBEC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TelegramCore; + productName = TelegramCore; + productReference = D09D8C011D4FAB1D0081DBEC /* TelegramCore.framework */; + productType = "com.apple.product-type.framework"; + }; + D09D8C091D4FAB1D0081DBEC /* TelegramCoreTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D09D8C181D4FAB1D0081DBEC /* Build configuration list for PBXNativeTarget "TelegramCoreTests" */; + buildPhases = ( + D09D8C061D4FAB1D0081DBEC /* Sources */, + D09D8C071D4FAB1D0081DBEC /* Frameworks */, + D09D8C081D4FAB1D0081DBEC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D09D8C0D1D4FAB1D0081DBEC /* PBXTargetDependency */, + ); + name = TelegramCoreTests; + productName = TelegramCoreTests; + productReference = D09D8C0A1D4FAB1D0081DBEC /* TelegramCoreTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + D0B418661D7E03D5004562A4 /* TelegramCoreMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0B4186C1D7E03D5004562A4 /* Build configuration list for PBXNativeTarget "TelegramCoreMac" */; + buildPhases = ( + D0B418621D7E03D5004562A4 /* Sources */, + D0B418631D7E03D5004562A4 /* Frameworks */, + D0B418641D7E03D5004562A4 /* Headers */, + D0B418651D7E03D5004562A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TelegramCoreMac; + productName = TelegramCoreMac; + productReference = D0B418671D7E03D5004562A4 /* TelegramCoreMac.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D09D8BF81D4FAB1D0081DBEC /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0800; + ORGANIZATIONNAME = Peter; + TargetAttributes = { + D09D8C001D4FAB1D0081DBEC = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = X834Q8SBVP; + DevelopmentTeamName = "TELEGRAM MESSENGER LLP"; + LastSwiftMigration = 0800; + ProvisioningStyle = Manual; + }; + D09D8C091D4FAB1D0081DBEC = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = X834Q8SBVP; + DevelopmentTeamName = "TELEGRAM MESSENGER LLP"; + ProvisioningStyle = Automatic; + }; + D0B418661D7E03D5004562A4 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = D09D8BFB1D4FAB1D0081DBEC /* Build configuration list for PBXProject "TelegramCore_Xcode" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = D09D8BF71D4FAB1D0081DBEC; + productRefGroup = D09D8C021D4FAB1D0081DBEC /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D09D8C001D4FAB1D0081DBEC /* TelegramCore */, + D09D8C091D4FAB1D0081DBEC /* TelegramCoreTests */, + D0B418661D7E03D5004562A4 /* TelegramCoreMac */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D09D8BFF1D4FAB1D0081DBEC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D09D8C081D4FAB1D0081DBEC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B418651D7E03D5004562A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D09D8BFC1D4FAB1D0081DBEC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D00DBBD71E64E41100DB5485 /* CreateSecretChat.swift in Sources */, + C2FD33EB1E696C78008D13D4 /* GroupsInCommon.swift in Sources */, + D0FA8BB01E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */, + D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */, + D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */, + D0CA8E4B227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift in Sources */, + D0DFD5DF1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */, + D093D7EE206413F600BC3599 /* SecureIdDataTypes.swift in Sources */, + D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */, + D033FEB01E61EB0200644997 /* PeerContactSettings.swift in Sources */, + D050F2511E4A59C200988324 /* JoinLink.swift in Sources */, + D07827C91E02F59C00071108 /* InstantPage.swift in Sources */, + D0458C881E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */, + D07827CB1E02F5B200071108 /* RichText.swift in Sources */, + D0613FD71E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */, + D0E412F4206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift in Sources */, + D0A3E447214802C7008ACEF6 /* VoipConfiguration.swift in Sources */, + D00D34451E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */, + D02D60AB206BA64100FEFE1E /* VerifySecureIdValue.swift in Sources */, + D00D343F1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */, + 090E778322A9862100CD99F5 /* ChannelOwnershipTransfer.swift in Sources */, + D03B0CE01D62249100955575 /* StoreMessage_Telegram.swift in Sources */, + D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */, + D023E67821540624008C27D1 /* UpdateMessageMedia.swift in Sources */, + D0EE7FC420986C5300981319 /* SecureIdPassportRegistrationValue.swift in Sources */, + D03B0CB91D62233400955575 /* Either.swift in Sources */, + D0D748021E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */, + 0962E66D21B5C56F00245FD9 /* JSON.swift in Sources */, + D0338740223BD48B007A2CE4 /* ContactsSettings.swift in Sources */, + D03B0CBD1D62234300955575 /* Regex.swift in Sources */, + D00BDA191EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */, + D0B843B91DA7FF30005F29E1 /* NBMetadataCoreTest.m in Sources */, + 09EDAD3A22131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift in Sources */, + D0EA188220D3D2B1001AEE19 /* RemoteStorageConfiguration.swift in Sources */, + D018EE002044939F00CBB130 /* SecretApiLayer73.swift in Sources */, + D09A2FE61D7CD4940018FB72 /* TelegramChannel.swift in Sources */, + D03B0D0E1D62255C00955575 /* UpdateGroup.swift in Sources */, + D053B4181F18DE4F00E2D58A /* AuthorSignatureMessageAttribute.swift in Sources */, + D0F3A89F1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */, + D01AC9231DD5E9A200E8160F /* ApplyUpdateMessage.swift in Sources */, + D0E8B8B32044706300605593 /* ForwardGame.swift in Sources */, + D0BE303D2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */, + D01A21AC1F38D10E00DDA104 /* SavedStickerItem.swift in Sources */, + D0642EF91F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift in Sources */, + D03B0CF71D62250800955575 /* TelegramMediaImage.swift in Sources */, + D054648E20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */, + C210DD621FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift in Sources */, + D06ECFC820B810D300C576C2 /* TermsOfService.swift in Sources */, + D0E23DDF1E8082A400B9B6D2 /* ArchivedStickerPacks.swift in Sources */, + D0546494207386D7002ECC1E /* SecureIdUtilityBillValue.swift in Sources */, + D0BC386E1E3FDAB70044D6FE /* CreateGroup.swift in Sources */, + D0FA8BB31E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */, + D098907F22942E3B0053F151 /* ActiveSessionsContext.swift in Sources */, + D026099E20C695AF006C34AC /* Wallpapers.swift in Sources */, + C205FEA81EB3B75900455808 /* ExportMessageLink.swift in Sources */, + D06AFE8920BF66BF00EA5124 /* DeserializeFunctionResponse.swift in Sources */, + D0E305AA1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */, + D0EE7FC72098853100981319 /* SecureIdTemporaryRegistrationValue.swift in Sources */, + C22EE61B1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */, + D053B3FC1F1651FA00E2D58A /* MonotonicTime.m in Sources */, + 090E779022AAABC600CD99F5 /* PeersNearby.swift in Sources */, + D073CE601DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, + D0AAD1A81E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift in Sources */, + C2366C831E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */, + 0900555621E4A96E0030924C /* Wallpaper.swift in Sources */, + C230BEB61EE9A3760029586C /* ChannelAdminEventLogs.swift in Sources */, + D0136309208F3B0900EB3653 /* SecureIdValueContentError.swift in Sources */, + D03B0D3D1D6319E200955575 /* Fetch.swift in Sources */, + D02D60A7206BA5F900FEFE1E /* SecureIdValue.swift in Sources */, + D0DF0C931D81AD09008AEB01 /* MessageUtils.swift in Sources */, + D03B0D681D631A8B00955575 /* RecentPeers.swift in Sources */, + D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */, + D0FA8BA71E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */, + D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */, + D093D7F920641AA500BC3599 /* SecureIdEmailValue.swift in Sources */, + D0C44B611FC616E200227BE0 /* SearchGroupMembers.swift in Sources */, + D0467D1520D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */, + D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */, + D018D3371E648ACF00C5E089 /* ChannelCreation.swift in Sources */, + D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */, + D0AF32221FAC95C20097362B /* StandaloneUploadedMedia.swift in Sources */, + D0F53BE91E784A4800117362 /* ChangeAccountPhoneNumber.swift in Sources */, + D0E35A0E1DE4953E00BC6096 /* FetchHttpResource.swift in Sources */, + D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */, + D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */, + D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */, + D0439B5D228ECB270067E026 /* RequestPhoneNumber.swift in Sources */, + D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */, + D0F3CC7D1DDE289E008148FA /* ResolvePeerByName.swift in Sources */, + D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */, + D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */, + D0DB7F031F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift in Sources */, + D0A472B61F4CBE8B00E0EEDA /* LoadedPeer.swift in Sources */, + D0AAD1B81E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift in Sources */, + D01A21A91F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift in Sources */, + D0338743223BD532007A2CE4 /* InitializeAccountAfterLogin.swift in Sources */, + D099EA1C1DE72867001AF5A8 /* PeerCommands.swift in Sources */, + D03B0CCE1D62239600955575 /* PhoneNumbers.swift in Sources */, + D00DBBDA1E64E67E00DB5485 /* UpdateSecretChat.swift in Sources */, + D0E23DD51E8042F500B9B6D2 /* FeaturedStickerPack.swift in Sources */, + D0FA8B981E1E955C001E855B /* SecretChatOutgoingOperation.swift in Sources */, + D0754D2A1EEE10FC00884F6E /* BotPaymentForm.swift in Sources */, + D0DF0C911D81A857008AEB01 /* ImageRepresentationsUtils.swift in Sources */, + D08CAA8C1ED81EDF0000FDA8 /* Localizations.swift in Sources */, + D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */, + D0F3A8A21E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */, + D0439B60228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift in Sources */, + D01C7ED61EF5E468008305F1 /* ProxySettings.swift in Sources */, + D049EAE81E44B67100A2CD3A /* RecentPeerItem.swift in Sources */, + D02ABC7B1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */, + C2E064681ECEEF0A00387BB8 /* TelegramMediaInvoice.swift in Sources */, + D0448C9F1E27F5EB005A61A7 /* Random.swift in Sources */, + D0C27B3F1F4B51D000A4E170 /* CachedStickerPack.swift in Sources */, + D0A8998F217A37A000759EE6 /* NotificationAutolockReportManager.swift in Sources */, + D0B843B21DA7FF30005F29E1 /* NBAsYouTypeFormatter.m in Sources */, + D07047B71F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift in Sources */, + D03B0CDB1D62245F00955575 /* ApiUtils.swift in Sources */, + D0B843C91DA7FF30005F29E1 /* NBPhoneNumberDesc.m in Sources */, + D08CAA801ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */, + D03B0CE61D6224A700955575 /* ReplyMessageAttribute.swift in Sources */, + D0D1026C2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */, + D0BEAF601E54ACF900BD963D /* AccountManager.swift in Sources */, + D0FA0ABD1E76C908005BB9B7 /* TwoStepVerification.swift in Sources */, + D02ABC7E1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */, + D0E412E1206AB24700BEE4A2 /* SecureFileMediaResource.swift in Sources */, + D0ADF911212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */, + D0448CA51E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */, + D0C26D661FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */, + D01843A82190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */, + D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */, + D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */, + C2E0646D1ECF171D00387BB8 /* TelegramMediaWebDocument.swift in Sources */, + D0B843811DA6EDAE005F29E1 /* CachedUserData.swift in Sources */, + D049EAD51E43D98500A2CD3A /* RecentMediaItem.swift in Sources */, + D09F9DCA20767D2C00DB4DE1 /* Api1.swift in Sources */, + D053B3FE1F16534400E2D58A /* MonotonicTime.swift in Sources */, + D0C50E341E93A86600F62E39 /* CallSessionManager.swift in Sources */, + D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */, + D08984FB2118816A00918162 /* Reachability.m in Sources */, + D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */, + D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */, + C23BC3871E9BE3CA00D79F92 /* ImportContact.swift in Sources */, + D00422D321677F4500719B67 /* ManagedAccountPresence.swift in Sources */, + D03B0D0A1D62255C00955575 /* Holes.swift in Sources */, + D05464972073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */, + D0633CDB2253C0D3003DD95F /* CloudMediaResourceParameters.swift in Sources */, + 0962E67521B6437600245FD9 /* SplitTest.swift in Sources */, + D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */, + D03B0D5E1D631A6900955575 /* Network.swift in Sources */, + D0B8438E1DA7D296005F29E1 /* CachedGroupParticipants.swift in Sources */, + D0B843BD1DA7FF30005F29E1 /* NBMetadataHelper.m in Sources */, + D03B0CF51D62250800955575 /* TelegramMediaContact.swift in Sources */, + D03B0CFB1D62250800955575 /* TelegramMediaWebpage.swift in Sources */, + 0962E66B21B5A41C00245FD9 /* ManagedSynchronizeAppLogEventsOperations.swift in Sources */, + D09A2FEB1D7CDC320018FB72 /* PeerAccessRestrictionInfo.swift in Sources */, + D0E35A101DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */, + D0E23DDA1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */, + D049EAD81E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */, + D0BE303A20619EE800FBE6D8 /* SecureIdForm.swift in Sources */, + D0448C991E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */, + D03DC9131F82F89D001D584C /* RegularChatState.swift in Sources */, + 0962E66721B59BAA00245FD9 /* ManagedAppConfigurationUpdates.swift in Sources */, + D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */, + D0B2F7742052DEF700D3BFB9 /* TelegramDeviceContactImportInfo.swift in Sources */, + C2366C891E4F40480097CCFF /* SupportPeerId.swift in Sources */, + D0AF32351FAE8C6B0097362B /* MultipeerManager.swift in Sources */, + D05A32E11E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */, + 0962E68121BAA20E00245FD9 /* SearchBotsConfiguration.swift in Sources */, + D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */, + D015E00E225CA61100CB9E8A /* FindChannelById.swift in Sources */, + D00BDA1C1EE5952A00C64C5E /* TelegramChannelBannedRights.swift in Sources */, + D03B0CF91D62250800955575 /* TelegramMediaMap.swift in Sources */, + D0E412E7206ABC7500BEE4A2 /* EncryptedMediaResource.swift in Sources */, + D0AB262621C2F991008F6685 /* TelegramMediaPoll.swift in Sources */, + D0BC38791E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift in Sources */, + D0FC195B2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift in Sources */, + D0B1671D1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift in Sources */, + D02B199021FB1D520094A764 /* RegisterNotificationToken.swift in Sources */, + D050F2101E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */, + D0C48F3C1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */, + D042C6831E8D9DF800C863B0 /* Unixtime.swift in Sources */, + D0C0B58A1ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift in Sources */, + D0EE7FC120986BF400981319 /* SecureIdInternalPassportValue.swift in Sources */, + D03B0D671D631A8B00955575 /* AccountViewTracker.swift in Sources */, + D0B843BB1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m in Sources */, + D0AB262B21C3CE80008F6685 /* Polls.swift in Sources */, + D0E412EA206AD18E00BEE4A2 /* DecryptedResourceData.swift in Sources */, + D03B0D101D62255C00955575 /* UpdatesApiUtils.swift in Sources */, + D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */, + D0FA8BAA1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */, + D00D97C71E32901700E5C2B6 /* PeerInputActivity.swift in Sources */, + D0FA8BAD1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, + D03B0CBF1D62234A00955575 /* Log.swift in Sources */, + C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */, + D0F8C3A02017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */, + D01C06B71FBBA269001561AB /* CanSendMessagesToPeer.swift in Sources */, + D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */, + D0EC559A2101ED0800D1992C /* DeleteMessages.swift in Sources */, + D02DADC12139A1FC00116225 /* ContactSyncManager.swift in Sources */, + D0C26D691FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */, + D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */, + D02395D61F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */, + D019B1CC1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */, + D081E10A217F5ADE003CD921 /* LocalizationPreview.swift in Sources */, + 09028386218E5DBB0067EFBD /* ManagedVoipConfigurationUpdates.swift in Sources */, + D03B0CD91D62245B00955575 /* PeerUtils.swift in Sources */, + D0F19F6620E6620D00EEC860 /* MultiplexedRequestManager.swift in Sources */, + D053B41B1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */, + D03B0CE41D62249F00955575 /* TextEntitiesMessageAttribute.swift in Sources */, + D0FA35081EA632E400E56FFA /* CollectCacheUsageStats.swift in Sources */, + D049EAEB1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift in Sources */, + D03B0CD31D62244300955575 /* Namespaces.swift in Sources */, + D01D6BF91E42A713006151C6 /* SearchStickers.swift in Sources */, + D08F4A691E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */, + D0575AF11E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */, + D07047B41F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */, + D0119CB020CA9EA800895300 /* MarkAllChatsAsRead.swift in Sources */, + D099E222229420D600561B75 /* BlockedPeersContext.swift in Sources */, + D0FA8BB91E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */, + D0561DE31E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */, + D0DF0C8A1D819C7E008AEB01 /* JoinChannel.swift in Sources */, + D051DB14215EC5A300F30F92 /* AppChangelogState.swift in Sources */, + D04554A621B43440007A6DD9 /* CancelAccountReset.swift in Sources */, + D04CAA5A1E83310D0047E51F /* MD5.swift in Sources */, + D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, + D05452071E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */, + D01C7F041EFC1C49008305F1 /* DeviceContact.swift in Sources */, + D0E412D7206A866B00BEE4A2 /* UploadSecureIdFile.swift in Sources */, + D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */, + D0AD02E31FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */, + D0B843971DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift in Sources */, + D0448CA21E291B14005A61A7 /* FetchSecretFileResource.swift in Sources */, + D08CAA871ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */, + D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */, + D09F9DCC20767D2C00DB4DE1 /* Api2.swift in Sources */, + D00C7CCC1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */, + D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */, + D093D7F520641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */, + D0B167231F9F972E00976B40 /* LoggingSettings.swift in Sources */, + D0BC387B1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */, + D0BB7C5A1E5C8074001527C3 /* ChannelParticipants.swift in Sources */, + D0448C8E1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */, + D0448C911E251F96005A61A7 /* SecretChatEncryption.swift in Sources */, + D0FA8BA11E1F99E1001E855B /* SecretChatFileReference.swift in Sources */, + D0223A981EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */, + D07827BB1E00451F00071108 /* SearchPeers.swift in Sources */, + 9FC8ADAB206BBFF10094F7B4 /* RecentWebSessions.swift in Sources */, + D0DC354E1DE368F7000195EB /* RequestChatContextResults.swift in Sources */, + D0BC38771E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift in Sources */, + D0B843851DA6EDC4005F29E1 /* CachedChannelData.swift in Sources */, + C29340F31F5080FA0074991E /* UpdateGroupSpecificStickerset.swift in Sources */, + D01C7ED31EF5DF83008305F1 /* LimitsConfiguration.swift in Sources */, + 9F06831021A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */, + D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */, + D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */, + D0BE304B20627D9800FBE6D8 /* AccessSecureId.swift in Sources */, + D0BEAF5D1E54941B00BD963D /* Authorization.swift in Sources */, + D0C26D6C1FE286C3004ABF18 /* FetchChatList.swift in Sources */, + C28D3CF020D3DA900027F4D6 /* DeepLinkInfo.swift in Sources */, + D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */, + D0E35A121DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, + D093D806206539D000BC3599 /* SaveSecureIdValue.swift in Sources */, + C239BE9C1E630CA700C2C453 /* UpdatePinnedMessage.swift in Sources */, + D032F5BC20EF84FD00037B6C /* FetchedMediaResource.swift in Sources */, + D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */, + D0B844531DAC0773005F29E1 /* TelegramUserPresence.swift in Sources */, + D08F4A661E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */, + D05A32E71E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */, + D0E41301206B9E6E00BEE4A2 /* SecureIdAddressValue.swift in Sources */, + D0B843871DA6F705005F29E1 /* UpdateCachedPeerData.swift in Sources */, + D0E412F1206B9BB700BEE4A2 /* SecureIdPassportValue.swift in Sources */, + D03B0D6D1D631AA300955575 /* ContactManagement.swift in Sources */, + D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */, + D03B0CF61D62250800955575 /* TelegramMediaFile.swift in Sources */, + D03B0CE81D6224AD00955575 /* ViewCountMessageAttribute.swift in Sources */, + D0FA35051EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */, + D03B0D0C1D62255C00955575 /* AccountStateManagementUtils.swift in Sources */, + D0633CD22253A528003DD95F /* ChatOnlineMembers.swift in Sources */, + D073CE5D1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift in Sources */, + D0FA8B9E1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift in Sources */, + D0561DEA1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */, + D099D7461EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */, + D0E412DC206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift in Sources */, + D0467D0B20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */, + D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */, + D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */, + 093857A92243D87900EB6A54 /* SynchronizeEmojiKeywordsOperation.swift in Sources */, + D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */, + D00580AE21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift in Sources */, + D00D34391E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */, + D00D97CA1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */, + 093857AB2243D88D00EB6A54 /* EmojiKeywords.swift in Sources */, + C2FD33E11E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */, + D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */, + D0AAD1AA1E32638500D5B9DE /* ApplyMaxReadIndexInteractively.swift in Sources */, + D0E68775207534CA0064BDB2 /* Api0.swift in Sources */, + D03B0D5C1D631A6900955575 /* Download.swift in Sources */, + D0C27B421F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */, + D054648B2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift in Sources */, + D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */, + D06CA13522772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */, + D03DC9101F82E344001D584C /* AccountStateReset.swift in Sources */, + D01B27A21E394D8B0022A4C0 /* PrivacySettings.swift in Sources */, + D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */, + D048B4AC20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */, + D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */, + D0CA3F84207391560042D2B6 /* SecureIdPadding.swift in Sources */, + D0FA8BB61E223C16001E855B /* SecretApiLayer8.swift in Sources */, + D0B843C71DA7FF30005F29E1 /* NBPhoneNumberDefines.m in Sources */, + D0F760D822202FE20074F7E5 /* ChannelStats.swift in Sources */, + 0962E66921B5A11100245FD9 /* SynchronizeAppLogEventsOperation.swift in Sources */, + D049EAF51E44DF3300A2CD3A /* AccountState.swift in Sources */, + C28725421EF967E700613564 /* NotificationInfoMessageAttribute.swift in Sources */, + D03B0D5D1D631A6900955575 /* MultipartFetch.swift in Sources */, + D058E0D11E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */, + D0BC38751E40A7F70044D6FE /* RemovePeerChat.swift in Sources */, + 093857A82243D87900EB6A54 /* ManagedSynchronizeEmojiKeywordsOperations.swift in Sources */, + D09F9DC820767D2C00DB4DE1 /* Api3.swift in Sources */, + D0529D2721A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */, + D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */, + D05A32E41E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */, + D01A21A61F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */, + D03E5E0C1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */, + D054649120738653002ECC1E /* SecureIdIDCardValue.swift in Sources */, + D018EE052045E95000CBB130 /* CheckPeerChatServiceActions.swift in Sources */, + D0F3A8A51E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */, + D03B0CD71D62245300955575 /* TelegramGroup.swift in Sources */, + D02609BF20C6EC08006C34AC /* Crypto.m in Sources */, + D0B8438C1DA7CF50005F29E1 /* BotInfo.swift in Sources */, + D033FEB31E61F3C000644997 /* ReportPeer.swift in Sources */, + D04D8FF4209A4B0700865719 /* NetworkSettings.swift in Sources */, + D0575AF41E9FFDDE006F2541 /* ManagedSynchronizeSavedGifsOperations.swift in Sources */, + C2F4ED1D1EC60064005F2696 /* RateCall.swift in Sources */, + D021E0E21DB5401A00C6B04F /* StickerManagement.swift in Sources */, + D051DB17215ECC4D00F30F92 /* AppChangelog.swift in Sources */, + D0BC38701E40853E0044D6FE /* UpdatePeers.swift in Sources */, + D0F3A8A81E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */, + D03B0CE21D62249B00955575 /* InlineBotMessageAttribute.swift in Sources */, + D0AB0B9A1D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift in Sources */, + D03B0D5B1D631A6900955575 /* Buffer.swift in Sources */, + D0B843891DA7AB96005F29E1 /* ExportedInvitation.swift in Sources */, + D0380DBA204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */, + D03B0E441D631E6600955575 /* NetworkLogging.m in Sources */, + D0528E651E65C82400E2FEF5 /* UpdateContactName.swift in Sources */, + D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */, + D018EE0220458E1E00CBB130 /* SecretChatLayerNegotiation.swift in Sources */, + D0C48F391E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */, + C239BE971E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift in Sources */, + 09EDAD382213120C0012A50B /* AutodownloadSettings.swift in Sources */, + D08984F22114B97400918162 /* ClearCloudDrafts.swift in Sources */, + D03B0CC11D62235000955575 /* StringFormat.swift in Sources */, + D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */, + D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */, + C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */, + D0529D2421A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */, + D0FA08BB2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */, + D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */, + D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */, + D0528E601E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */, + D08CAA841ED8164B0000FDA8 /* Localization.swift in Sources */, + D0528E5A1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */, + D0FA8BA41E1FA341001E855B /* SecretChatKeychain.swift in Sources */, + D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */, + D0E412EE206AF65500BEE4A2 /* GrantSecureIdAccess.swift in Sources */, + D02ABC811E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift in Sources */, + D03B0D651D631A8B00955575 /* Account.swift in Sources */, + D0AB0B941D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift in Sources */, + D08774FC1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift in Sources */, + D03B0CF41D62250800955575 /* TelegramMediaAction.swift in Sources */, + D041E3F81E535A88008C24B4 /* RemovePeerMember.swift in Sources */, + D076F8892296D8E9004F895A /* ManageChannelDiscussionGroup.swift in Sources */, + D0B417C11D7DCEEF004562A4 /* ApiGroupOrChannel.swift in Sources */, + D041E3F51E535464008C24B4 /* AddPeerMember.swift in Sources */, + D0AF32311FACEDEC0097362B /* CoreSettings.swift in Sources */, + D054649A20738760002ECC1E /* SecureIdRentalAgreementValue.swift in Sources */, + D0B843BF1DA7FF30005F29E1 /* NBNumberFormat.m in Sources */, + D0E305A71E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */, + D0B843C51DA7FF30005F29E1 /* NBPhoneNumber.m in Sources */, + D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */, + D03B0D081D62255C00955575 /* ChannelState.swift in Sources */, + D08984F521187ECA00918162 /* NetworkType.swift in Sources */, + C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */, + 0962E66F21B6147600245FD9 /* AppConfiguration.swift in Sources */, + D07047BA1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */, + D07E413F208A769D00FCA8F0 /* ProxyServersStatuses.swift in Sources */, + D0C0B58D1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D09D8C061D4FAB1D0081DBEC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D09D8C101D4FAB1D0081DBEC /* TelegramCoreTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B418621D7E03D5004562A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D014193922AE6B85008667CB /* ChannelOwnershipTransfer.swift in Sources */, + D014193A22AE6B85008667CB /* PeersNearby.swift in Sources */, + D076F88A2296D8F6004F895A /* ManageChannelDiscussionGroup.swift in Sources */, + 9F1BC1AB2244CFED00F21815 /* EmojiKeywords.swift in Sources */, + 9F1BC1AC2244CFED00F21815 /* SynchronizeEmojiKeywordsOperation.swift in Sources */, + 9F1BC1AD2244CFED00F21815 /* ManagedSynchronizeEmojiKeywordsOperations.swift in Sources */, + 9F7D42262223FF49007B68BB /* AutodownloadSettings.swift in Sources */, + 9F7D42272223FF49007B68BB /* ManagedAutodownloadSettingsUpdates.swift in Sources */, + 9F153D1021E8E0A200B95D82 /* Wallpaper.swift in Sources */, + 9F4EEF9E21DCF6E7002C3B33 /* ManagedVoipConfigurationUpdates.swift in Sources */, + 9F4EEF9F21DCF6E7002C3B33 /* ManagedAppConfigurationUpdates.swift in Sources */, + 9F4EEFA021DCF6E7002C3B33 /* SynchronizeAppLogEventsOperation.swift in Sources */, + 9F4EEFA121DCF6E7002C3B33 /* ManagedSynchronizeAppLogEventsOperations.swift in Sources */, + 9F4EEF9B21DCF66F002C3B33 /* JSON.swift in Sources */, + 9F4EEF9C21DCF66F002C3B33 /* AppConfiguration.swift in Sources */, + 9F4EEF9D21DCF66F002C3B33 /* SearchBotsConfiguration.swift in Sources */, + 9FAA268820D457A300D26CF3 /* RemoteStorageConfiguration.swift in Sources */, + C28D3CF120D3DAA30027F4D6 /* DeepLinkInfo.swift in Sources */, + 9FC8ADAC206BC00A0094F7B4 /* RecentWebSessions.swift in Sources */, + 9FC8ADA9206BBD000094F7B4 /* SaveSecureIdValue.swift in Sources */, + 9F10CE8C20613CDB002DD61A /* TelegramDeviceContactImportInfo.swift in Sources */, + 9F10CE8B20613C78002DD61A /* SecretApiLayer73.swift in Sources */, + C29340F41F5081280074991E /* UpdateGroupSpecificStickerset.swift in Sources */, + C25638021E79E7FC00311607 /* TwoStepVerification.swift in Sources */, + D00DBBD81E64E41100DB5485 /* CreateSecretChat.swift in Sources */, + C2FD33EC1E696C79008D13D4 /* GroupsInCommon.swift in Sources */, + C239BE9D1E630CB300C2C453 /* UpdatePinnedMessage.swift in Sources */, + C239BE981E62F0D200C2C453 /* LoadMessagesIfNecessary.swift in Sources */, + D01C7ED41EF5DF83008305F1 /* LimitsConfiguration.swift in Sources */, + D051DB15215EC5A300F30F92 /* AppChangelogState.swift in Sources */, + C26A37EF1E5E0C41006977AC /* ChannelParticipants.swift in Sources */, + D00D343D1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */, + D02609C020C6EC08006C34AC /* Crypto.m in Sources */, + D0AB262721C2F991008F6685 /* TelegramMediaPoll.swift in Sources */, + D0C26D6A1FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */, + D01C7F051EFC1C49008305F1 /* DeviceContact.swift in Sources */, + D050F26A1E4A5B6D00988324 /* ManagedGlobalNotificationSettings.swift in Sources */, + D050F26B1E4A5B6D00988324 /* ApplyMaxReadIndexInteractively.swift in Sources */, + D033FEB11E61EB0200644997 /* PeerContactSettings.swift in Sources */, + D0458C891E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */, + D050F26C1E4A5B6D00988324 /* UpdatePeers.swift in Sources */, + D08984F621187ECA00918162 /* NetworkType.swift in Sources */, + D050F26D1E4A5B6D00988324 /* CreateGroup.swift in Sources */, + D0575AF51E9FFDDE006F2541 /* ManagedSynchronizeSavedGifsOperations.swift in Sources */, + D00D34461E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */, + D0E412E8206ABC7500BEE4A2 /* EncryptedMediaResource.swift in Sources */, + D00D34401E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */, + D050F26E1E4A5B6D00988324 /* RemovePeerChat.swift in Sources */, + D0613FD81E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */, + D0DB7F041F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift in Sources */, + D01D6BFA1E42A718006151C6 /* SearchStickers.swift in Sources */, + D0D748031E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */, + D0B167241F9F972E00976B40 /* LoggingSettings.swift in Sources */, + D0E41302206B9E6E00BEE4A2 /* SecureIdAddressValue.swift in Sources */, + C2A315C01E2E776A00D89000 /* RequestStartBot.swift in Sources */, + D0642EFA1F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift in Sources */, + D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */, + D08984F32114B97400918162 /* ClearCloudDrafts.swift in Sources */, + D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */, + D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */, + D03DC9111F82E344001D584C /* AccountStateReset.swift in Sources */, + D0B1671E1F9EA2C300976B40 /* ChatHistoryPreloadManager.swift in Sources */, + D050F2111E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */, + D050F2631E4A5AEB00988324 /* SynchronizePinnedChatsOperation.swift in Sources */, + D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */, + D0E23DE01E8082A400B9B6D2 /* ArchivedStickerPacks.swift in Sources */, + D02D60AC206BA64100FEFE1E /* VerifySecureIdValue.swift in Sources */, + D0119CB120CA9EA800895300 /* MarkAllChatsAsRead.swift in Sources */, + D050F2521E4A59C200988324 /* JoinLink.swift in Sources */, + D018EE0320458E1E00CBB130 /* SecretChatLayerNegotiation.swift in Sources */, + D0F7B1E91E045C87007EB8A5 /* PeerCommands.swift in Sources */, + D00D97C81E32901700E5C2B6 /* PeerInputActivity.swift in Sources */, + D0754D2B1EEE10FC00884F6E /* BotPaymentForm.swift in Sources */, + D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */, + D0E412EF206AF65500BEE4A2 /* GrantSecureIdAccess.swift in Sources */, + C22EE61C1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */, + D09F9DCB20767D2C00DB4DE1 /* Api1.swift in Sources */, + D0B418AC1D7E0597004562A4 /* Network.swift in Sources */, + D04CAA5B1E83310D0047E51F /* MD5.swift in Sources */, + D0B844141DAB91CD005F29E1 /* PhoneNumbers.swift in Sources */, + D0E305AB1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */, + D00D97CB1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */, + D0B844491DAB91FD005F29E1 /* ManagedChatListHoles.swift in Sources */, + D03C53711DAD5CA9004C17B3 /* CachedGroupParticipants.swift in Sources */, + D07047B81F3DF2CD00F6A8D4 /* ManagedConsumePersonalMessagesActions.swift in Sources */, + C2366C841E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */, + C2E0646E1ECF171E00387BB8 /* TelegramMediaWebDocument.swift in Sources */, + D03C53671DAD5CA9004C17B3 /* ApiUtils.swift in Sources */, + D0223A9C1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */, + D0AAD1B91E326FE200D5B9DE /* ManagedAutoremoveMessageOperations.swift in Sources */, + D001F3F21E128A1C007A8C60 /* UpdateGroup.swift in Sources */, + D0338744223BD532007A2CE4 /* InitializeAccountAfterLogin.swift in Sources */, + D0F7B1EB1E045C87007EB8A5 /* ResolvePeerByName.swift in Sources */, + D018D3381E648ACF00C5E089 /* ChannelCreation.swift in Sources */, + D0F53BEA1E784A4800117362 /* ChangeAccountPhoneNumber.swift in Sources */, + C2E064691ECEEF0B00387BB8 /* TelegramMediaInvoice.swift in Sources */, + D001F3EE1E128A1C007A8C60 /* AccountStateManager.swift in Sources */, + D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */, + C205FEA91EB3B75900455808 /* ExportMessageLink.swift in Sources */, + D0448CA31E291B14005A61A7 /* FetchSecretFileResource.swift in Sources */, + D0B8442F1DAB91E0005F29E1 /* NBMetadataHelper.m in Sources */, + D0B8444C1DAB91FD005F29E1 /* UpdateCachedPeerData.swift in Sources */, + D0FA8B9F1E1F973B001E855B /* SecretChatIncomingEncryptedOperation.swift in Sources */, + D03C536C1DAD5CA9004C17B3 /* TelegramChannel.swift in Sources */, + D0B418951D7E0580004562A4 /* TelegramMediaContact.swift in Sources */, + D0F3CC7A1DDE2859008148FA /* RequestMessageActionCallback.swift in Sources */, + D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */, + D0E23DD61E8042F500B9B6D2 /* FeaturedStickerPack.swift in Sources */, + C230BEB71EE9A3760029586C /* ChannelAdminEventLogs.swift in Sources */, + D00DBBDB1E64E67E00DB5485 /* UpdateSecretChat.swift in Sources */, + D0BE303E2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */, + D0448C921E251F96005A61A7 /* SecretChatEncryption.swift in Sources */, + D00BDA1D1EE5952A00C64C5E /* TelegramChannelBannedRights.swift in Sources */, + D0E35A141DE4C69C00BC6096 /* FetchHttpResource.swift in Sources */, + D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */, + D03C536A1DAD5CA9004C17B3 /* TelegramUser.swift in Sources */, + D001F3EA1E128A1C007A8C60 /* TelegramPeerNotificationSettings.swift in Sources */, + D0E412F5206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift in Sources */, + D0467D0C20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */, + D0FA8BA81E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */, + C23BC3881E9BE3CB00D79F92 /* ImportContact.swift in Sources */, + D0B85AC61F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */, + D0E412F2206B9BB700BEE4A2 /* SecureIdPassportValue.swift in Sources */, + D001F3EB1E128A1C007A8C60 /* EnqueueMessage.swift in Sources */, + D01A21A71F38CDC700DDA104 /* SynchronizeSavedStickersOperation.swift in Sources */, + D0E68776207534CA0064BDB2 /* Api0.swift in Sources */, + D00C7CEC1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */, + D048B4AD20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */, + D0B844481DAB91FD005F29E1 /* ManagedMessageHistoryHoles.swift in Sources */, + D0F3CC7B1DDE2859008148FA /* RequestEditMessage.swift in Sources */, + D049EAEC1E44B71B00A2CD3A /* RecentlySearchedPeerIds.swift in Sources */, + D0F19F6720E6621000EEC860 /* MultiplexedRequestManager.swift in Sources */, + D02D60A8206BA5F900FEFE1E /* SecureIdValue.swift in Sources */, + D0FA8B991E1E955C001E855B /* SecretChatOutgoingOperation.swift in Sources */, + D001F3F01E128A1C007A8C60 /* AccountStateManagementUtils.swift in Sources */, + D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */, + D0CA3F85207391560042D2B6 /* SecureIdPadding.swift in Sources */, + D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */, + D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */, + D093D7EF206413F600BC3599 /* SecureIdDataTypes.swift in Sources */, + D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */, + D06CA13622772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */, + D0C44B621FC616E200227BE0 /* SearchGroupMembers.swift in Sources */, + D0F3A8A61E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */, + D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */, + D00D34431E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */, + D049EAE91E44B67100A2CD3A /* RecentPeerItem.swift in Sources */, + D026099F20C695AF006C34AC /* Wallpapers.swift in Sources */, + D099E223229420D600561B75 /* BlockedPeersContext.swift in Sources */, + D0FA35091EA632E400E56FFA /* CollectCacheUsageStats.swift in Sources */, + D0E412EB206AD18E00BEE4A2 /* DecryptedResourceData.swift in Sources */, + D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */, + D0C50E351E93A86600F62E39 /* CallSessionManager.swift in Sources */, + D0A3E448214802C7008ACEF6 /* VoipConfiguration.swift in Sources */, + D018EE062045E95000CBB130 /* CheckPeerChatServiceActions.swift in Sources */, + D081E10B217F5ADE003CD921 /* LocalizationPreview.swift in Sources */, + D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */, + D0C27B431F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */, + D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */, + D0C0B58E1ED9DC5A000F4D2C /* SynchronizeLocalizationUpdatesOperation.swift in Sources */, + D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, + D0B418961D7E0580004562A4 /* TelegramMediaFile.swift in Sources */, + D08CAA881ED81DD40000FDA8 /* LocalizationInfo.swift in Sources */, + D099D74A1EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */, + D0AF32231FAC95C20097362B /* StandaloneUploadedMedia.swift in Sources */, + D04554A721B43440007A6DD9 /* CancelAccountReset.swift in Sources */, + D001F3EC1E128A1C007A8C60 /* Holes.swift in Sources */, + D0B4189B1D7E0580004562A4 /* TelegramMediaWebpage.swift in Sources */, + D00C7CE11E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */, + D0E23DDB1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */, + D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */, + D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */, + D07047B51F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */, + D0448C8F1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */, + D093D7F620641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */, + D0C26D6D1FE286C3004ABF18 /* FetchChatList.swift in Sources */, + D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */, + D093D7FA20641AA500BC3599 /* SecureIdEmailValue.swift in Sources */, + D05A32E21E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */, + D0613FD01E60520700202CDB /* ChannelMembers.swift in Sources */, + D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */, + C2366C8A1E4F40480097CCFF /* SupportPeerId.swift in Sources */, + D08CAA811ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */, + D0DA1D331F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */, + D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */, + D0C48F3D1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */, + D0F3A8A01E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */, + D050F2601E4A5AD500988324 /* AutoremoveTimeoutMessageAttribute.swift in Sources */, + D07E4140208A769D00FCA8F0 /* ProxyServersStatuses.swift in Sources */, + D049EAD91E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */, + D0EE7FC220986BF400981319 /* SecureIdInternalPassportValue.swift in Sources */, + D0B418A61D7E0592004562A4 /* CloudFileMediaResource.swift in Sources */, + D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */, + D06AFE8A20BF66BF00EA5124 /* DeserializeFunctionResponse.swift in Sources */, + D03C536D1DAD5CA9004C17B3 /* ApiGroupOrChannel.swift in Sources */, + D051DB18215ECC4D00F30F92 /* AppChangelog.swift in Sources */, + D01C06B81FBBA269001561AB /* CanSendMessagesToPeer.swift in Sources */, + D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */, + D0B418A91D7E0597004562A4 /* Buffer.swift in Sources */, + D02ABC821E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift in Sources */, + C2FD33E51E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */, + D0BE304C20627D9800FBE6D8 /* AccessSecureId.swift in Sources */, + D0B8442E1DAB91E0005F29E1 /* NBMetadataCoreTestMapper.m in Sources */, + D01A21AD1F38D10E00DDA104 /* SavedStickerItem.swift in Sources */, + D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */, + D019B1CD1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */, + C2F4ED1E1EC60064005F2696 /* RateCall.swift in Sources */, + D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */, + D0B844121DAB91CD005F29E1 /* Log.swift in Sources */, + D03C53721DAD5CA9004C17B3 /* CachedUserData.swift in Sources */, + D0D1026D2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */, + D0AF32321FACEDEC0097362B /* CoreSettings.swift in Sources */, + D073CE6B1DCBCF17007511FD /* ReplyMessageAttribute.swift in Sources */, + D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */, + D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */, + D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */, + D0529D2521A4123400D7C3C4 /* SynchronizeRecentlyUsedMediaOperations.swift in Sources */, + D06ECFC920B810D300C576C2 /* TermsOfService.swift in Sources */, + 9F06831121A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */, + D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */, + D0AB262C21C3CE80008F6685 /* Polls.swift in Sources */, + D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */, + D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */, + D00580AF21E2A08900CB7CD3 /* AccountEnvironmentAttribute.swift in Sources */, + D05452081E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */, + D0561DE41E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */, + D042C6841E8D9DF800C863B0 /* Unixtime.swift in Sources */, + D0DC35521DE36908000195EB /* ChatContextResult.swift in Sources */, + D0F7AB301DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */, + D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */, + D073CE6D1DCBCF17007511FD /* InlineBotMessageAttribute.swift in Sources */, + D033FEB71E61F3F900644997 /* BlockedPeers.swift in Sources */, + D0448C9A1E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */, + D0E412D8206A866B00BEE4A2 /* UploadSecureIdFile.swift in Sources */, + D050F2611E4A5AE700988324 /* PrivacySettings.swift in Sources */, + C210DD631FBDB90800F673D8 /* SourceReferenceMessageAttribute.swift in Sources */, + D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */, + D0DC35511DE36908000195EB /* RequestChatContextResults.swift in Sources */, + D0FA08BC2046B37900DD23FC /* ContentPrivacySettings.swift in Sources */, + D08CAA8D1ED81EDF0000FDA8 /* Localizations.swift in Sources */, + D013630A208F6E2800EB3653 /* SecureIdValueContentError.swift in Sources */, + D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */, + D02DADC22139A1FC00116225 /* ContactSyncManager.swift in Sources */, + D001F3EF1E128A1C007A8C60 /* AccountIntermediateState.swift in Sources */, + D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */, + D00C7CCD1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */, + D0A472B71F4CBE8B00E0EEDA /* LoadedPeer.swift in Sources */, + D03C536E1DAD5CA9004C17B3 /* PhoneNumber.swift in Sources */, + D0338741223BD48B007A2CE4 /* ContactsSettings.swift in Sources */, + D0BC387C1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */, + D0528E6B1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */, + D0E8B8B42044706300605593 /* ForwardGame.swift in Sources */, + D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */, + D0B844321DAB91E0005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */, + D0BEAF5E1E54941B00BD963D /* Authorization.swift in Sources */, + D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */, + D03C53701DAD5CA9004C17B3 /* ExportedInvitation.swift in Sources */, + D0FA35061EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */, + D08F4A671E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */, + D05A32E81E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */, + D0F7B1E31E045C7B007EB8A5 /* RichText.swift in Sources */, + D0FA8BB11E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */, + D0B418AA1D7E0597004562A4 /* Download.swift in Sources */, + D001F3F41E128A1C007A8C60 /* UpdatesApiUtils.swift in Sources */, + D015E00F225CA61100CB9E8A /* FindChannelById.swift in Sources */, + D04D8FF5209A4B0700865719 /* NetworkSettings.swift in Sources */, + D05464982073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */, + D0B4188E1D7E0578004562A4 /* StoreMessage_Telegram.swift in Sources */, + D0B844461DAB91FD005F29E1 /* RecentPeers.swift in Sources */, + D0E412E2206AB24700BEE4A2 /* SecureFileMediaResource.swift in Sources */, + D0439B5E228ECB270067E026 /* RequestPhoneNumber.swift in Sources */, + D03C53681DAD5CA9004C17B3 /* PeerUtils.swift in Sources */, + D0BE303B20619EE800FBE6D8 /* SecureIdForm.swift in Sources */, + D07047BB1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */, + D0380DBB204EF306000414AB /* MessageMediaPreuploadManager.swift in Sources */, + D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */, + D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */, + D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */, + D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */, + D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, + D054649B20738760002ECC1E /* SecureIdRentalAgreementValue.swift in Sources */, + D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */, + D0AD02E41FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */, + D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */, + D0439B61228EDE430067E026 /* ContentRequiresValidationMessageAttribute.swift in Sources */, + D0633CD32253A528003DD95F /* ChatOnlineMembers.swift in Sources */, + D08984FC2118816A00918162 /* Reachability.m in Sources */, + D0B844471DAB91FD005F29E1 /* ManagedServiceViews.swift in Sources */, + D0F3A8A91E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */, + D00D343A1E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */, + D03C53691DAD5CA9004C17B3 /* PeerAccessRestrictionInfo.swift in Sources */, + C2FD33E21E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */, + D0B8440E1DAB91CD005F29E1 /* MessageUtils.swift in Sources */, + D0FA8BAB1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */, + D0C26D671FE022DB004ABF18 /* SynchronizeGroupedPeersOperation.swift in Sources */, + D0B418BA1D7E05BB004562A4 /* NetworkLogging.m in Sources */, + D03C536B1DAD5CA9004C17B3 /* TelegramGroup.swift in Sources */, + D0E412DD206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift in Sources */, + D0B418941D7E0580004562A4 /* TelegramMediaAction.swift in Sources */, + D0B8442C1DAB91E0005F29E1 /* NBMetadataCoreMapper.m in Sources */, + D0FA8BB71E223C16001E855B /* SecretApiLayer8.swift in Sources */, + D0EC559B2101ED0800D1992C /* DeleteMessages.swift in Sources */, + D073CE6A1DCBCF17007511FD /* ViewCountMessageAttribute.swift in Sources */, + D0B418AB1D7E0597004562A4 /* MultipartFetch.swift in Sources */, + D01A21AA1F38CDDC00DDA104 /* ManagedSynchronizeSavedStickersOperations.swift in Sources */, + D0546495207386D7002ECC1E /* SecureIdUtilityBillValue.swift in Sources */, + D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */, + D032F5BD20EF84FD00037B6C /* FetchedMediaResource.swift in Sources */, + D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */, + D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */, + D02395D71F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */, + D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */, + D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */, + D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */, + D0F760D922202FE20074F7E5 /* ChannelStats.swift in Sources */, + D0ADF912212B00DD00310BBC /* SecureIdConfiguration.swift in Sources */, + C28725431EF967E700613564 /* NotificationInfoMessageAttribute.swift in Sources */, + D0A89990217A37A000759EE6 /* NotificationAutolockReportManager.swift in Sources */, + D054648C2073854A002ECC1E /* SecureIdPersonalDetailsValue.swift in Sources */, + D0F8C3A12017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */, + D09F9DC920767D2C00DB4DE1 /* Api3.swift in Sources */, + D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */, + D058E0D21E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */, + D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */, + D0FA8BBA1E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */, + D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */, + D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, + D0FA8BB41E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */, + D0F3A8A31E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */, + D098908022942E3B0053F151 /* ActiveSessionsContext.swift in Sources */, + D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */, + D0633CDC2253C0D3003DD95F /* CloudMediaResourceParameters.swift in Sources */, + D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */, + D054648F20738626002ECC1E /* SecureIdDriversLicenseValue.swift in Sources */, + D0529D2821A4141800D7C3C4 /* ManagedSynchronizeRecentlyUsedMediaOperations.swift in Sources */, + D050F2641E4A5AEB00988324 /* ManagedSynchronizePinnedChatsOperations.swift in Sources */, + D0575AF21E9FFA5D006F2541 /* SynchronizeSavedGifsOperation.swift in Sources */, + D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */, + D0EE7FC82098853100981319 /* SecureIdTemporaryRegistrationValue.swift in Sources */, + D00422D421677F4500719B67 /* ManagedAccountPresence.swift in Sources */, + D023E67921540624008C27D1 /* UpdateMessageMedia.swift in Sources */, + D053B4191F18DE5000E2D58A /* AuthorSignatureMessageAttribute.swift in Sources */, + D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */, + D0C48F3A1E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */, + D049EAD61E43D98500A2CD3A /* RecentMediaItem.swift in Sources */, + D0EE7FC520986C5300981319 /* SecureIdPassportRegistrationValue.swift in Sources */, + D0C0B58B1ED9DA6B000F4D2C /* ManagedLocalizationUpdatesOperations.swift in Sources */, + D0B844331DAB91E0005F29E1 /* NBPhoneNumber.m in Sources */, + D001F3F51E128A1C007A8C60 /* PendingMessageManager.swift in Sources */, + D0C27B401F4B51D000A4E170 /* CachedStickerPack.swift in Sources */, + D001F3F61E128A1C007A8C60 /* PendingMessageUploadedContent.swift in Sources */, + D01C7ED71EF5E468008305F1 /* ProxySettings.swift in Sources */, + C2366C871E4F403C0097CCFF /* AddressNames.swift in Sources */, + D02ABC7F1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */, + D0528E611E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */, + D0FC195C2020D1CA00FEDBB2 /* PeerGroupMessageStateVersionAttribute.swift in Sources */, + D0CA8E4C227209C4008A74C3 /* ManagedSynchronizeGroupMessageStats.swift in Sources */, + D08CAA851ED8164B0000FDA8 /* Localization.swift in Sources */, + D0528E5B1E658B3600E2FEF5 /* ManagedLocalInputActivities.swift in Sources */, + D0FA8BA51E1FA341001E855B /* SecretChatKeychain.swift in Sources */, + D0F7B1E71E045C87007EB8A5 /* JoinChannel.swift in Sources */, + D0E652201E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */, + D0FA8BA21E1F99E1001E855B /* SecretChatFileReference.swift in Sources */, + D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */, + D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */, + D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */, + D01843A92190C28100278AFF /* ConfirmTwoStepRecoveryEmail.swift in Sources */, + D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */, + D049EAF61E44DF3300A2CD3A /* AccountState.swift in Sources */, + D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */, + D041E3F61E535464008C24B4 /* AddPeerMember.swift in Sources */, + D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */, + D0E305A81E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */, + D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, + D0B844431DAB91FD005F29E1 /* Account.swift in Sources */, + D08CAA7E1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */, + D054649220738653002ECC1E /* SecureIdIDCardValue.swift in Sources */, + D09F9DCD20767D2C00DB4DE1 /* Api2.swift in Sources */, + D0448CA01E27F5EB005A61A7 /* Random.swift in Sources */, + C251D7441E65E50500283EDE /* StickerSetInstallation.swift in Sources */, + D053B41C1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + D09D8C0D1D4FAB1D0081DBEC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D09D8C001D4FAB1D0081DBEC /* TelegramCore */; + targetProxy = D09D8C0C1D4FAB1D0081DBEC /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + C22069BE1E8EB4A200E82730 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseHockeyapp; + }; + C22069BF1E8EB4A200E82730 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = ReleaseHockeyapp; + }; + C22069C01E8EB4A200E82730 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = ReleaseHockeyapp; + }; + C22069C11E8EB4A200E82730 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = ReleaseHockeyapp; + }; + D021D508219CB1E40064BEBA /* DebugFork */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugFork; + }; + D021D509219CB1E40064BEBA /* DebugFork */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = DebugFork; + }; + D021D50A219CB1E40064BEBA /* DebugFork */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = DebugFork; + }; + D021D50B219CB1E40064BEBA /* DebugFork */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + FRAMEWORK_VERSION = A; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = DebugFork; + }; + D06706551D51162400DED3E3 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseAppStore; + }; + D06706561D51162400DED3E3 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = ReleaseAppStore; + }; + D06706571D51162400DED3E3 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = ReleaseAppStore; + }; + D0924FE81FE52C12003F693F /* ReleaseHockeyappInternal */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseHockeyappInternal; + }; + D0924FE91FE52C12003F693F /* ReleaseHockeyappInternal */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = ReleaseHockeyappInternal; + }; + D0924FEA1FE52C12003F693F /* ReleaseHockeyappInternal */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = ReleaseHockeyappInternal; + }; + D0924FEB1FE52C12003F693F /* ReleaseHockeyappInternal */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = ReleaseHockeyappInternal; + }; + D09D8C131D4FAB1D0081DBEC /* DebugHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugHockeyapp; + }; + D09D8C141D4FAB1D0081DBEC /* DebugAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugAppStore; + }; + D09D8C161D4FAB1D0081DBEC /* DebugHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = DebugHockeyapp; + }; + D09D8C171D4FAB1D0081DBEC /* DebugAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = DebugAppStore; + }; + D09D8C191D4FAB1D0081DBEC /* DebugHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = DebugHockeyapp; + }; + D09D8C1A1D4FAB1D0081DBEC /* DebugAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = DebugAppStore; + }; + D0ADF934212B3ADA00310BBC /* DebugAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugAppStoreLLC; + }; + D0ADF935212B3ADA00310BBC /* DebugAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = DebugAppStoreLLC; + }; + D0ADF936212B3ADA00310BBC /* DebugAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = DebugAppStoreLLC; + }; + D0ADF937212B3ADA00310BBC /* DebugAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = DebugAppStoreLLC; + }; + D0B4186D1D7E03D5004562A4 /* DebugHockeyapp */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + FRAMEWORK_VERSION = A; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = DebugHockeyapp; + }; + D0B4186E1D7E03D5004562A4 /* DebugAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + OTHER_SWIFT_FLAGS = "-DDEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = DebugAppStore; + }; + D0B4186F1D7E03D5004562A4 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = ReleaseAppStore; + }; + D0CE6EF5213DC30700BCD44B /* ReleaseAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseAppStoreLLC; + }; + D0CE6EF6213DC30700BCD44B /* ReleaseAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = TelegramCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib", + "$(PROJECT_DIR)/third-party/libwebp/lib", + ); + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap"; + OTHER_LDFLAGS = "-Wl,-dead_strip"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = all; + SWIFT_VERSION = 4.0; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include"; + }; + name = ReleaseAppStoreLLC; + }; + D0CE6EF7213DC30700BCD44B /* ReleaseAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + INFOPLIST_FILE = TelegramCoreTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = ReleaseAppStoreLLC; + }; + D0CE6EF8213DC30700BCD44B /* ReleaseAppStoreLLC */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = TelegramCoreMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap"; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = ReleaseAppStoreLLC; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D09D8BFB1D4FAB1D0081DBEC /* Build configuration list for PBXProject "TelegramCore_Xcode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D09D8C131D4FAB1D0081DBEC /* DebugHockeyapp */, + D021D508219CB1E40064BEBA /* DebugFork */, + D09D8C141D4FAB1D0081DBEC /* DebugAppStore */, + D0ADF934212B3ADA00310BBC /* DebugAppStoreLLC */, + C22069BE1E8EB4A200E82730 /* ReleaseHockeyapp */, + D0924FE81FE52C12003F693F /* ReleaseHockeyappInternal */, + D06706551D51162400DED3E3 /* ReleaseAppStore */, + D0CE6EF5213DC30700BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = DebugAppStore; + }; + D09D8C151D4FAB1D0081DBEC /* Build configuration list for PBXNativeTarget "TelegramCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D09D8C161D4FAB1D0081DBEC /* DebugHockeyapp */, + D021D509219CB1E40064BEBA /* DebugFork */, + D09D8C171D4FAB1D0081DBEC /* DebugAppStore */, + D0ADF935212B3ADA00310BBC /* DebugAppStoreLLC */, + C22069BF1E8EB4A200E82730 /* ReleaseHockeyapp */, + D0924FE91FE52C12003F693F /* ReleaseHockeyappInternal */, + D06706561D51162400DED3E3 /* ReleaseAppStore */, + D0CE6EF6213DC30700BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = DebugAppStore; + }; + D09D8C181D4FAB1D0081DBEC /* Build configuration list for PBXNativeTarget "TelegramCoreTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D09D8C191D4FAB1D0081DBEC /* DebugHockeyapp */, + D021D50A219CB1E40064BEBA /* DebugFork */, + D09D8C1A1D4FAB1D0081DBEC /* DebugAppStore */, + D0ADF936212B3ADA00310BBC /* DebugAppStoreLLC */, + C22069C01E8EB4A200E82730 /* ReleaseHockeyapp */, + D0924FEA1FE52C12003F693F /* ReleaseHockeyappInternal */, + D06706571D51162400DED3E3 /* ReleaseAppStore */, + D0CE6EF7213DC30700BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = DebugAppStore; + }; + D0B4186C1D7E03D5004562A4 /* Build configuration list for PBXNativeTarget "TelegramCoreMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0B4186D1D7E03D5004562A4 /* DebugHockeyapp */, + D021D50B219CB1E40064BEBA /* DebugFork */, + D0B4186E1D7E03D5004562A4 /* DebugAppStore */, + D0ADF937212B3ADA00310BBC /* DebugAppStoreLLC */, + C22069C11E8EB4A200E82730 /* ReleaseHockeyapp */, + D0924FEB1FE52C12003F693F /* ReleaseHockeyappInternal */, + D0B4186F1D7E03D5004562A4 /* ReleaseAppStore */, + D0CE6EF8213DC30700BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = DebugAppStore; + }; +/* End XCConfigurationList section */ + }; + rootObject = D09D8BF81D4FAB1D0081DBEC /* Project object */; +} diff --git a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..48eb199cdd --- /dev/null +++ b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/xcshareddata/xcschemes/TelegramCore.xcscheme b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/xcshareddata/xcschemes/TelegramCore.xcscheme new file mode 100644 index 0000000000..0eb420f857 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/xcshareddata/xcschemes/TelegramCore.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h new file mode 100755 index 0000000000..3ea02a8b07 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h @@ -0,0 +1,38 @@ +// +// NBAsYouTypeFormatter.h +// libPhoneNumber +// +// Created by ishtar on 13. 2. 25.. +// + +#import + + +@class NBAsYouTypeFormatter; + + +@interface NBAsYouTypeFormatter : NSObject + +- (id)initWithRegionCode:(NSString *)regionCode; +- (id)initWithRegionCodeForTest:(NSString *)regionCode; +- (id)initWithRegionCode:(NSString *)regionCode bundle:(NSBundle *)bundle; +- (id)initWithRegionCodeForTest:(NSString *)regionCode bundle:(NSBundle *)bundle; + +- (NSString *)inputString:(NSString *)string; +- (NSString *)inputStringAndRememberPosition:(NSString *)string; + +- (NSString *)inputDigit:(NSString*)nextChar; +- (NSString *)inputDigitAndRememberPosition:(NSString*)nextChar; + +- (NSString *)removeLastDigit; +- (NSString *)removeLastDigitAndRememberPosition; + +- (NSInteger)getRememberedPosition; + +- (void)clear; + +@property (nonatomic, assign, readonly) BOOL isSuccessfulFormatting; + +@property (nonatomic, strong, readonly) NSString *regionPrefix; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.m new file mode 100755 index 0000000000..5b73386866 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBAsYouTypeFormatter.m @@ -0,0 +1,1297 @@ +// +// NBAsYouTypeFormatter.m +// libPhoneNumber +// +// Created by ishtar on 13. 2. 25.. +// + +#import "NBAsYouTypeFormatter.h" +#import "NBPhoneNumberDefines.h" + +#import "NBMetadataHelper.h" + +#import "NBPhoneNumberUtil.h" +#import "NBPhoneMetaData.h" +#import "NBNumberFormat.h" + + +@interface NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index; +@end + +@implementation NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index { + @synchronized(self) { + if (index >= [self count]) return nil; + id res = [self objectAtIndex:index]; + if (res == nil || (NSNull*)res == [NSNull null]) { + return nil; + } + return res; + } +} +@end + + +@interface NBAsYouTypeFormatter () + +@property (nonatomic, strong, readwrite) NSString *DIGIT_PLACEHOLDER_; +@property (nonatomic, assign, readwrite) NSString *SEPARATOR_BEFORE_NATIONAL_NUMBER_; +@property (nonatomic, strong, readwrite) NSString *currentOutput_, *currentFormattingPattern_; +@property (nonatomic, strong, readwrite) NSString *defaultCountry_; +@property (nonatomic, strong, readwrite) NSString *nationalPrefixExtracted_; +@property (nonatomic, strong, readwrite) NSMutableString *formattingTemplate_, *accruedInput_, *prefixBeforeNationalNumber_, *accruedInputWithoutFormatting_, *nationalNumber_; +@property (nonatomic, strong, readwrite) NSRegularExpression *DIGIT_PATTERN_, *NATIONAL_PREFIX_SEPARATORS_PATTERN_, *CHARACTER_CLASS_PATTERN_, *STANDALONE_DIGIT_PATTERN_; +@property (nonatomic, strong, readwrite) NSRegularExpression *ELIGIBLE_FORMAT_PATTERN_; +@property (nonatomic, assign, readwrite) BOOL ableToFormat_, inputHasFormatting_, isCompleteNumber_, isExpectingCountryCallingCode_, shouldAddSpaceAfterNationalPrefix_; +@property (nonatomic, strong, readwrite) NBPhoneNumberUtil *phoneUtil_; +@property (nonatomic, assign, readwrite) NSUInteger lastMatchPosition_, originalPosition_, positionToRemember_; +@property (nonatomic, assign, readwrite) NSUInteger MIN_LEADING_DIGITS_LENGTH_; +@property (nonatomic, strong, readwrite) NSMutableArray *possibleFormats_; +@property (nonatomic, strong, readwrite) NBPhoneMetaData *currentMetaData_, *defaultMetaData_, *EMPTY_METADATA_; + +@end + + +@implementation NBAsYouTypeFormatter + +- (id)init +{ + self = [super init]; + + if (self) { + _isSuccessfulFormatting = NO; + /** + * The digits that have not been entered yet will be represented by a \u2008, + * the punctuation space. + * @const + * @type {string} + * @private + */ + self.DIGIT_PLACEHOLDER_ = @"\u2008"; + + /** + * Character used when appropriate to separate a prefix, such as a long NDD or a + * country calling code, from the national number. + * @const + * @type {string} + * @private + */ + self.SEPARATOR_BEFORE_NATIONAL_NUMBER_ = @" "; + + /** + * This is the minimum length of national number accrued that is required to + * trigger the formatter. The first element of the leadingDigitsPattern of + * each numberFormat contains a regular expression that matches up to this + * number of digits. + * @const + * @type {number} + * @private + */ + self.MIN_LEADING_DIGITS_LENGTH_ = 3; + + /** + * @type {string} + * @private + */ + self.currentOutput_ = @""; + + /** + * @type {!goog.string.StringBuffer} + * @private + */ + self.formattingTemplate_ = [NSMutableString stringWithString:@""]; + + NSError *anError = nil; + + /** + * @type {RegExp} + * @private + */ + self.DIGIT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:self.DIGIT_PLACEHOLDER_ options:0 error:&anError]; + + /** + * A set of characters that, if found in a national prefix formatting rules, are + * an indicator to us that we should separate the national prefix from the + * number when formatting. + * @const + * @type {RegExp} + * @private + */ + self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"[- ]" options:0 error:&anError]; + + /** + * A pattern that is used to match character classes in regular expressions. + * An example of a character class is [1-4]. + * @const + * @type {RegExp} + * @private + */ + self.CHARACTER_CLASS_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"\\[([^\\[\\]])*\\]" options:0 error:&anError]; + + /** + * Any digit in a regular expression that actually denotes a digit. For + * example, in the regular expression 80[0-2]\d{6,10}, the first 2 digits + * (8 and 0) are standalone digits, but the rest are not. + * Two look-aheads are needed because the number following \\d could be a + * two-digit number, since the phone number can be as long as 15 digits. + * @const + * @type {RegExp} + * @private + */ + self.STANDALONE_DIGIT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"\\d(?=[^,}][^,}])" options:0 error:&anError]; + + /** + * A pattern that is used to determine if a numberFormat under availableFormats + * is eligible to be used by the AYTF. It is eligible when the format element + * under numberFormat contains groups of the dollar sign followed by a single + * digit, separated by valid phone number punctuation. This prevents invalid + * punctuation (such as the star sign in Israeli star numbers) getting into the + * output of the AYTF. + * @const + * @type {RegExp} + * @private + */ + NSString *eligible_format = @"^[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~]*(\\$\\d[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~]*)+$"; + self.ELIGIBLE_FORMAT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:eligible_format options:0 error:&anError]; + + /** + * The pattern from numberFormat that is currently used to create + * formattingTemplate. + * @type {string} + * @private + */ + self.currentFormattingPattern_ = @""; + + /** + * @type {!goog.string.StringBuffer} + * @private + */ + self.accruedInput_ = [NSMutableString stringWithString:@""]; + + /** + * @type {!goog.string.StringBuffer} + * @private + */ + self.accruedInputWithoutFormatting_ = [NSMutableString stringWithString:@""]; + + /** + * This indicates whether AsYouTypeFormatter is currently doing the + * formatting. + * @type {BOOL} + * @private + */ + self.ableToFormat_ = YES; + + /** + * Set to YES when users enter their own formatting. AsYouTypeFormatter will + * do no formatting at all when this is set to YES. + * @type {BOOL} + * @private + */ + self.inputHasFormatting_ = NO; + + /** + * This is set to YES when we know the user is entering a full national + * significant number, since we have either detected a national prefix or an + * international dialing prefix. When this is YES, we will no longer use + * local number formatting patterns. + * @type {BOOL} + * @private + */ + self.isCompleteNumber_ = NO; + + /** + * @type {BOOL} + * @private + */ + self.isExpectingCountryCallingCode_ = NO; + + /** + * @type {number} + * @private + */ + self.lastMatchPosition_ = 0; + + /** + * The position of a digit upon which inputDigitAndRememberPosition is most + * recently invoked, as found in the original sequence of characters the user + * entered. + * @type {number} + * @private + */ + self.originalPosition_ = 0; + + /** + * The position of a digit upon which inputDigitAndRememberPosition is most + * recently invoked, as found in accruedInputWithoutFormatting. + * entered. + * @type {number} + * @private + */ + self.positionToRemember_ = 0; + + /** + * This contains anything that has been entered so far preceding the national + * significant number, and it is formatted (e.g. with space inserted). For + * example, this can contain IDD, country code, and/or NDD, etc. + * @type {!goog.string.StringBuffer} + * @private + */ + self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""]; + + /** + * @type {BOOL} + * @private + */ + self.shouldAddSpaceAfterNationalPrefix_ = NO; + + /** + * This contains the national prefix that has been extracted. It contains only + * digits without formatting. + * @type {string} + * @private + */ + self.nationalPrefixExtracted_ = @""; + + /** + * @type {!goog.string.StringBuffer} + * @private + */ + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + + /** + * @type {Array.} + * @private + */ + self.possibleFormats_ = [[NSMutableArray alloc] init]; + } + + return self; +} + +/** + * Constructs an AsYouTypeFormatter for the specific region. + * + * @param {string} regionCode the ISO 3166-1 two-letter region code that denotes + * the region where the phone number is being entered. + * @constructor + */ + +- (id)initWithRegionCode:(NSString*)regionCode +{ + return [self initWithRegionCode:regionCode bundle:[NSBundle mainBundle]]; +} + +- (id)initWithRegionCodeForTest:(NSString*)regionCode +{ + return [self initWithRegionCodeForTest:regionCode bundle:[NSBundle mainBundle]]; +} + +- (id)initWithRegionCode:(NSString*)regionCode bundle:(NSBundle *)bundle +{ + self = [self init]; + if (self) { + /** + * @private + * @type {i18n.phonenumbers.PhoneNumberUtil} + */ + self.phoneUtil_ = [[NBPhoneNumberUtil alloc] init]; + self.defaultCountry_ = regionCode; + self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_]; + /** + * @type {i18n.phonenumbers.PhoneMetadata} + * @private + */ + self.defaultMetaData_ = self.currentMetaData_; + + /** + * @const + * @type {i18n.phonenumbers.PhoneMetadata} + * @private + */ + self.EMPTY_METADATA_ = [[NBPhoneMetaData alloc] init]; + [self.EMPTY_METADATA_ setInternationalPrefix:@"NA"]; + } + + return self; + +} + +- (id)initWithRegionCodeForTest:(NSString*)regionCode bundle:(NSBundle *)bundle +{ + self = [self init]; + + if (self) { + self.phoneUtil_ = [[NBPhoneNumberUtil alloc] init]; + + self.defaultCountry_ = regionCode; + self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_]; + self.defaultMetaData_ = self.currentMetaData_; + self.EMPTY_METADATA_ = [[NBPhoneMetaData alloc] init]; + [self.EMPTY_METADATA_ setInternationalPrefix:@"NA"]; + } + + return self; +} + +/** + * The metadata needed by this class is the same for all regions sharing the + * same country calling code. Therefore, we return the metadata for "main" + * region for this country calling code. + * @param {string} regionCode an ISO 3166-1 two-letter region code. + * @return {i18n.phonenumbers.PhoneMetadata} main metadata for this region. + * @private + */ +- (NBPhoneMetaData*)getMetadataForRegion_:(NSString*)regionCode +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + /** @type {number} */ + NSNumber *countryCallingCode = [self.phoneUtil_ getCountryCodeForRegion:regionCode]; + /** @type {string} */ + NSString *mainCountry = [self.phoneUtil_ getRegionCodeForCountryCode:countryCallingCode]; + /** @type {i18n.phonenumbers.PhoneMetadata} */ + NBPhoneMetaData *metadata = [helper getMetadataForRegion:mainCountry]; + if (metadata != nil) { + return metadata; + } + // Set to a default instance of the metadata. This allows us to function with + // an incorrect region code, even if formatting only works for numbers + // specified with '+'. + return self.EMPTY_METADATA_; +}; + + +/** + * @return {BOOL} YES if a new template is created as opposed to reusing the + * existing template. + * @private + */ +- (BOOL)maybeCreateNewTemplate_ +{ + // When there are multiple available formats, the formatter uses the first + // format where a formatting template could be created. + /** @type {number} */ + unsigned int possibleFormatsLength = (unsigned int)[self.possibleFormats_ count]; + for (unsigned int i = 0; i < possibleFormatsLength; ++i) + { + /** @type {i18n.phonenumbers.NumberFormat} */ + NBNumberFormat *numberFormat = [self.possibleFormats_ safeObjectAtIndex:i]; + /** @type {string} */ + NSString *pattern = numberFormat.pattern; + + if (!pattern.length || [self.currentFormattingPattern_ isEqualToString:pattern]) { + return NO; + } + + if ([self createFormattingTemplate_:numberFormat ]) + { + self.currentFormattingPattern_ = pattern; + NSRange nationalPrefixRange = NSMakeRange(0, [numberFormat.nationalPrefixFormattingRule length]); + if (nationalPrefixRange.length > 0) { + NSTextCheckingResult *matchResult = + [self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ firstMatchInString:numberFormat.nationalPrefixFormattingRule + options:0 + range:nationalPrefixRange]; + self.shouldAddSpaceAfterNationalPrefix_ = (matchResult != nil); + } else { + self.shouldAddSpaceAfterNationalPrefix_ = NO; + } + // With a new formatting template, the matched position using the old + // template needs to be reset. + self.lastMatchPosition_ = 0; + return YES; + } + } + self.ableToFormat_ = NO; + return NO; +}; + + +/** + * @param {string} leadingThreeDigits first three digits of entered number. + * @private + */ +- (void)getAvailableFormats_:(NSString*)leadingDigits +{ + /** @type {Array.} */ + BOOL isIntlNumberFormats = (self.isCompleteNumber_ && self.currentMetaData_.intlNumberFormats.count > 0); + NSMutableArray *formatList = isIntlNumberFormats ? self.currentMetaData_.intlNumberFormats : self.currentMetaData_.numberFormats; + + /** @type {number} */ + unsigned int formatListLength = (unsigned int)formatList.count; + + for (unsigned int i = 0; i < formatListLength; ++i) + { + /** @type {i18n.phonenumbers.NumberFormat} */ + NBNumberFormat *format = [formatList safeObjectAtIndex:i]; + /** @type {BOOL} */ + BOOL nationalPrefixIsUsedByCountry = (self.currentMetaData_.nationalPrefix && self.currentMetaData_.nationalPrefix.length > 0); + + if (!nationalPrefixIsUsedByCountry || self.isCompleteNumber_ || format.nationalPrefixOptionalWhenFormatting || + [self.phoneUtil_ formattingRuleHasFirstGroupOnly:format.nationalPrefixFormattingRule]) + { + if ([self isFormatEligible_:format.format]) { + [self.possibleFormats_ addObject:format]; + } + } + } + + [self narrowDownPossibleFormats_:leadingDigits]; +}; + + +/** + * @param {string} format + * @return {BOOL} + * @private + */ +- (BOOL)isFormatEligible_:(NSString*)format +{ + if ( !format.length ) { + return NO; + } + NSTextCheckingResult *matchResult = + [self.ELIGIBLE_FORMAT_PATTERN_ firstMatchInString:format options:0 range:NSMakeRange(0, [format length])]; + return (matchResult != nil); +}; + + +/** + * @param {string} leadingDigits + * @private + */ +- (void)narrowDownPossibleFormats_:(NSString *)leadingDigits +{ + /** @type {Array.} */ + NSMutableArray *possibleFormats = [[NSMutableArray alloc] init]; + /** @type {number} */ + NSUInteger indexOfLeadingDigitsPattern = (unsigned int)leadingDigits.length - self.MIN_LEADING_DIGITS_LENGTH_; + /** @type {number} */ + NSUInteger possibleFormatsLength = (unsigned int)self.possibleFormats_.count; + + for (NSUInteger i = 0; i < possibleFormatsLength; ++i) + { + /** @type {i18n.phonenumbers.NumberFormat} */ + NBNumberFormat *format = [self.possibleFormats_ safeObjectAtIndex:i]; + + if (format.leadingDigitsPatterns.count == 0) { + // Keep everything that isn't restricted by leading digits. + [possibleFormats addObject:format]; + continue; + } + + /** @type {number} */ + NSInteger lastLeadingDigitsPattern = MIN(indexOfLeadingDigitsPattern, format.leadingDigitsPatterns.count - 1); + + /** @type {string} */ + NSString *leadingDigitsPattern = [format.leadingDigitsPatterns safeObjectAtIndex:lastLeadingDigitsPattern]; + + if ([self.phoneUtil_ stringPositionByRegex:leadingDigits regex:leadingDigitsPattern] == 0) { + [possibleFormats addObject:format]; + } + } + self.possibleFormats_ = possibleFormats; +}; + + +/** + * @param {i18n.phonenumbers.NumberFormat} format + * @return {BOOL} + * @private + */ +- (BOOL)createFormattingTemplate_:(NBNumberFormat*)format +{ + /** @type {string} */ + NSString *numberPattern = format.pattern; + + // The formatter doesn't format numbers when numberPattern contains '|', e.g. + // (20|3)\d{4}. In those cases we quickly return. + NSRange stringRange = [numberPattern rangeOfString:@"|"]; + if (stringRange.location != NSNotFound) { + return NO; + } + + // Replace anything in the form of [..] with \d + numberPattern = [self.CHARACTER_CLASS_PATTERN_ stringByReplacingMatchesInString:numberPattern + options:0 range:NSMakeRange(0, [numberPattern length]) + withTemplate:@"\\\\d"]; + + // Replace any standalone digit (not the one in d{}) with \d + numberPattern = [self.STANDALONE_DIGIT_PATTERN_ stringByReplacingMatchesInString:numberPattern + options:0 range:NSMakeRange(0, [numberPattern length]) + withTemplate:@"\\\\d"]; + self.formattingTemplate_ = [NSMutableString stringWithString:@""]; + + /** @type {string} */ + NSString *tempTemplate = [self getFormattingTemplate_:numberPattern numberFormat:format.format]; + if (tempTemplate.length > 0) { + [self.formattingTemplate_ appendString:tempTemplate]; + return YES; + } + return NO; +}; + + +/** + * Gets a formatting template which can be used to efficiently format a + * partial number where digits are added one by one. + * + * @param {string} numberPattern + * @param {string} numberFormat + * @return {string} + * @private + */ +- (NSString*)getFormattingTemplate_:(NSString*)numberPattern numberFormat:(NSString*)numberFormat +{ + // Creates a phone number consisting only of the digit 9 that matches the + // numberPattern by applying the pattern to the longestPhoneNumber string. + /** @type {string} */ + NSString *longestPhoneNumber = @"999999999999999"; + + /** @type {Array.} */ + NSArray *m = [self.phoneUtil_ matchedStringByRegex:longestPhoneNumber regex:numberPattern]; + + // this match will always succeed + /** @type {string} */ + NSString *aPhoneNumber = [m safeObjectAtIndex:0]; + // No formatting template can be created if the number of digits entered so + // far is longer than the maximum the current formatting rule can accommodate. + if (aPhoneNumber.length < self.nationalNumber_.length) { + return @""; + } + // Formats the number according to numberFormat + /** @type {string} */ + NSString *template = [self.phoneUtil_ replaceStringByRegex:aPhoneNumber regex:numberPattern withTemplate:numberFormat]; + + // Replaces each digit with character DIGIT_PLACEHOLDER + template = [self.phoneUtil_ replaceStringByRegex:template regex:@"9" withTemplate:self.DIGIT_PLACEHOLDER_]; + return template; +}; + + +/** + * Clears the internal state of the formatter, so it can be reused. + */ +- (void)clear +{ + self.currentOutput_ = @""; + self.accruedInput_ = [NSMutableString stringWithString:@""]; + self.accruedInputWithoutFormatting_ = [NSMutableString stringWithString:@""]; + self.formattingTemplate_ = [NSMutableString stringWithString:@""]; + self.lastMatchPosition_ = 0; + self.currentFormattingPattern_ = @""; + self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""]; + self.nationalPrefixExtracted_ = @""; + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + self.ableToFormat_ = YES; + self.inputHasFormatting_ = NO; + self.positionToRemember_ = 0; + self.originalPosition_ = 0; + self.isCompleteNumber_ = NO; + self.isExpectingCountryCallingCode_ = NO; + [self.possibleFormats_ removeAllObjects]; + self.shouldAddSpaceAfterNationalPrefix_ = NO; + + if (self.currentMetaData_ != self.defaultMetaData_) { + self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_]; + } +} + +- (NSString*)removeLastDigitAndRememberPosition +{ + NSString *accruedInputWithoutFormatting = [self.accruedInput_ copy]; + [self clear]; + + NSString *result = @""; + + if (accruedInputWithoutFormatting.length <= 0) { + return result; + } + + for (unsigned int i=0; i 0) { + // The formatting patterns are already chosen. + /** @type {string} */ + NSString *tempNationalNumber = [self inputDigitHelper_:nextChar]; + // See if the accrued digits can be formatted properly already. If not, + // use the results from inputDigitHelper, which does formatting based on + // the formatting pattern chosen. + /** @type {string} */ + NSString *formattedNumber = [self attemptToFormatAccruedDigits_]; + if (formattedNumber.length > 0) { + _isSuccessfulFormatting = YES; + return formattedNumber; + } + + [self narrowDownPossibleFormats_:self.nationalNumber_]; + + if ([self maybeCreateNewTemplate_]) { + _isSuccessfulFormatting = YES; + return [self inputAccruedNationalNumber_]; + } + + if (self.ableToFormat_) { + _isSuccessfulFormatting = YES; + return [self appendNationalNumber_:tempNationalNumber]; + } else { + _isSuccessfulFormatting = NO; + return self.accruedInput_; + } + } + else { + _isSuccessfulFormatting = NO; + return [self attemptToChooseFormattingPattern_]; + } + } + + _isSuccessfulFormatting = NO; +}; + + +/** + * @return {string} + * @private + */ +- (NSString*)attemptToChoosePatternWithPrefixExtracted_ +{ + self.ableToFormat_ = YES; + self.isExpectingCountryCallingCode_ = NO; + [self.possibleFormats_ removeAllObjects]; + return [self attemptToChooseFormattingPattern_]; +}; + + +/** + * Some national prefixes are a substring of others. If extracting the shorter + * NDD doesn't result in a number we can format, we try to see if we can extract + * a longer version here. + * @return {BOOL} + * @private + */ +- (BOOL)ableToExtractLongerNdd_ +{ + if (self.nationalPrefixExtracted_.length > 0) + { + // Put the extracted NDD back to the national number before attempting to + // extract a new NDD. + /** @type {string} */ + NSString *nationalNumberStr = [NSString stringWithString:self.nationalNumber_]; + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + [self.nationalNumber_ appendString:self.nationalPrefixExtracted_]; + [self.nationalNumber_ appendString:nationalNumberStr]; + // Remove the previously extracted NDD from prefixBeforeNationalNumber. We + // cannot simply set it to empty string because people sometimes incorrectly + // enter national prefix after the country code, e.g. +44 (0)20-1234-5678. + /** @type {string} */ + NSString *prefixBeforeNationalNumberStr = [NSString stringWithString:self.prefixBeforeNationalNumber_]; + NSRange lastRange = [prefixBeforeNationalNumberStr rangeOfString:self.nationalPrefixExtracted_ options:NSBackwardsSearch]; + /** @type {number} */ + unsigned int indexOfPreviousNdd = (unsigned int)lastRange.location; + self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""]; + [self.prefixBeforeNationalNumber_ appendString:[prefixBeforeNationalNumberStr substringWithRange:NSMakeRange(0, indexOfPreviousNdd)]]; + } + + return self.nationalPrefixExtracted_ != [self removeNationalPrefixFromNationalNumber_]; +}; + + +/** + * @param {string} nextChar + * @return {BOOL} + * @private + */ +- (BOOL)isDigitOrLeadingPlusSign_:(NSString*)nextChar +{ + NSString *digitPattern = [NSString stringWithFormat:@"([%@])", NB_VALID_DIGITS_STRING]; + NSString *plusPattern = [NSString stringWithFormat:@"[%@]+", NB_PLUS_CHARS]; + + BOOL isDigitPattern = [[self.phoneUtil_ matchesByRegex:nextChar regex:digitPattern] count] > 0; + BOOL isPlusPattern = [[self.phoneUtil_ matchesByRegex:nextChar regex:plusPattern] count] > 0; + + return isDigitPattern || (self.accruedInput_.length == 1 && isPlusPattern); +}; + + +/** + * Check to see if there is an exact pattern match for these digits. If so, we + * should use this instead of any other formatting template whose + * leadingDigitsPattern also matches the input. + * @return {string} + * @private + */ +- (NSString*)attemptToFormatAccruedDigits_ +{ + /** @type {string} */ + NSString *nationalNumber = [NSString stringWithString:self.nationalNumber_]; + + /** @type {number} */ + unsigned int possibleFormatsLength = (unsigned int)self.possibleFormats_.count; + for (unsigned int i = 0; i < possibleFormatsLength; ++i) + { + /** @type {i18n.phonenumbers.NumberFormat} */ + NBNumberFormat *numberFormat = self.possibleFormats_[i]; + /** @type {string} */ + NSString * pattern = numberFormat.pattern; + /** @type {RegExp} */ + NSString *patternRegExp = [NSString stringWithFormat:@"^(?:%@)$", pattern]; + BOOL isPatternRegExp = [[self.phoneUtil_ matchesByRegex:nationalNumber regex:patternRegExp] count] > 0; + if (isPatternRegExp) { + if (numberFormat.nationalPrefixFormattingRule.length > 0) { + NSArray *matches = [self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ matchesInString:numberFormat.nationalPrefixFormattingRule + options:0 + range:NSMakeRange(0, numberFormat.nationalPrefixFormattingRule.length)]; + self.shouldAddSpaceAfterNationalPrefix_ = [matches count] > 0; + } else { + self.shouldAddSpaceAfterNationalPrefix_ = NO; + } + + /** @type {string} */ + NSString *formattedNumber = [self.phoneUtil_ replaceStringByRegex:nationalNumber + regex:pattern + withTemplate:numberFormat.format]; + return [self appendNationalNumber_:formattedNumber]; + } + } + return @""; +}; + + +/** + * Combines the national number with any prefix (IDD/+ and country code or + * national prefix) that was collected. A space will be inserted between them if + * the current formatting template indicates this to be suitable. + * @param {string} nationalNumber The number to be appended. + * @return {string} The combined number. + * @private + */ +- (NSString*)appendNationalNumber_:(NSString*)nationalNumber +{ + /** @type {number} */ + unsigned int prefixBeforeNationalNumberLength = (unsigned int)self.prefixBeforeNationalNumber_.length; + unichar blank_char = [self.SEPARATOR_BEFORE_NATIONAL_NUMBER_ characterAtIndex:0]; + if (self.shouldAddSpaceAfterNationalPrefix_ && prefixBeforeNationalNumberLength > 0 && + [self.prefixBeforeNationalNumber_ characterAtIndex:prefixBeforeNationalNumberLength - 1] != blank_char) + { + // We want to add a space after the national prefix if the national prefix + // formatting rule indicates that this would normally be done, with the + // exception of the case where we already appended a space because the NDD + // was surprisingly long. + + return [NSString stringWithFormat:@"%@%@%@", self.prefixBeforeNationalNumber_, self.SEPARATOR_BEFORE_NATIONAL_NUMBER_, nationalNumber]; + } else { + return [NSString stringWithFormat:@"%@%@", self.prefixBeforeNationalNumber_, nationalNumber]; + } +}; + + +/** + * Returns the current position in the partially formatted phone number of the + * character which was previously passed in as the parameter of + * {@link #inputDigitAndRememberPosition}. + * + * @return {number} + */ +- (NSInteger)getRememberedPosition +{ + if (!self.ableToFormat_) { + return self.originalPosition_; + } + /** @type {number} */ + NSInteger accruedInputIndex = 0; + /** @type {number} */ + NSInteger currentOutputIndex = 0; + /** @type {string} */ + NSString *accruedInputWithoutFormatting = self.accruedInputWithoutFormatting_; + /** @type {string} */ + NSString *currentOutput = self.currentOutput_; + + while (accruedInputIndex < self.positionToRemember_ && currentOutputIndex < currentOutput.length) + { + if ([accruedInputWithoutFormatting characterAtIndex:accruedInputIndex] == [currentOutput characterAtIndex:currentOutputIndex]) + { + accruedInputIndex++; + } + currentOutputIndex++; + } + return currentOutputIndex; +}; + + +/** + * Attempts to set the formatting template and returns a string which contains + * the formatted version of the digits entered so far. + * + * @return {string} + * @private + */ +- (NSString*)attemptToChooseFormattingPattern_ +{ + /** @type {string} */ + NSString *nationalNumber = [self.nationalNumber_ copy]; + // We start to attempt to format only when as least MIN_LEADING_DIGITS_LENGTH + // digits of national number (excluding national prefix) have been entered. + if (nationalNumber.length >= self.MIN_LEADING_DIGITS_LENGTH_) { + [self getAvailableFormats_:nationalNumber]; + // See if the accrued digits can be formatted properly already. + NSString *formattedNumber = [self attemptToFormatAccruedDigits_]; + if (formattedNumber.length > 0) { + return formattedNumber; + } + return [self maybeCreateNewTemplate_] ? [self inputAccruedNationalNumber_] : self.accruedInput_; + } else { + return [self appendNationalNumber_:nationalNumber]; + } +} + + +/** + * Invokes inputDigitHelper on each digit of the national number accrued, and + * returns a formatted string in the end. + * + * @return {string} + * @private + */ +- (NSString*)inputAccruedNationalNumber_ +{ + /** @type {string} */ + NSString *nationalNumber = [self.nationalNumber_ copy]; + /** @type {number} */ + unsigned int lengthOfNationalNumber = (unsigned int)nationalNumber.length; + if (lengthOfNationalNumber > 0) { + /** @type {string} */ + NSString *tempNationalNumber = @""; + for (unsigned int i = 0; i < lengthOfNationalNumber; i++) + { + tempNationalNumber = [self inputDigitHelper_:[NSString stringWithFormat: @"%C", [nationalNumber characterAtIndex:i]]]; + } + return self.ableToFormat_ ? [self appendNationalNumber_:tempNationalNumber] : self.accruedInput_; + } else { + return self.prefixBeforeNationalNumber_; + } +}; + + +/** + * @return {BOOL} YES if the current country is a NANPA country and the + * national number begins with the national prefix. + * @private + */ +- (BOOL)isNanpaNumberWithNationalPrefix_ +{ + // For NANPA numbers beginning with 1[2-9], treat the 1 as the national + // prefix. The reason is that national significant numbers in NANPA always + // start with [2-9] after the national prefix. Numbers beginning with 1[01] + // can only be short/emergency numbers, which don't need the national prefix. + if (![self.currentMetaData_.countryCode isEqual:@1]) { + return NO; + } + + /** @type {string} */ + NSString *nationalNumber = [self.nationalNumber_ copy]; + return ([nationalNumber characterAtIndex:0] == '1') && ([nationalNumber characterAtIndex:1] != '0') && + ([nationalNumber characterAtIndex:1] != '1'); +}; + + +/** + * Returns the national prefix extracted, or an empty string if it is not + * present. + * @return {string} + * @private + */ +- (NSString*)removeNationalPrefixFromNationalNumber_ +{ + /** @type {string} */ + NSString *nationalNumber = [self.nationalNumber_ copy]; + /** @type {number} */ + unsigned int startOfNationalNumber = 0; + + if ([self isNanpaNumberWithNationalPrefix_]) { + startOfNationalNumber = 1; + [self.prefixBeforeNationalNumber_ appendString:@"1"]; + [self.prefixBeforeNationalNumber_ appendFormat:@"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]; + self.isCompleteNumber_ = YES; + } + else if (self.currentMetaData_.nationalPrefixForParsing != nil && self.currentMetaData_.nationalPrefixForParsing.length > 0) + { + /** @type {RegExp} */ + NSString *nationalPrefixForParsing = [NSString stringWithFormat:@"^(?:%@)", self.currentMetaData_.nationalPrefixForParsing]; + /** @type {Array.} */ + NSArray *m = [self.phoneUtil_ matchedStringByRegex:nationalNumber regex:nationalPrefixForParsing]; + NSString *firstString = [m safeObjectAtIndex:0]; + if (m != nil && firstString != nil && firstString.length > 0) { + // When the national prefix is detected, we use international formatting + // rules instead of national ones, because national formatting rules could + // contain local formatting rules for numbers entered without area code. + self.isCompleteNumber_ = YES; + startOfNationalNumber = (unsigned int)firstString.length; + [self.prefixBeforeNationalNumber_ appendString:[nationalNumber substringWithRange:NSMakeRange(0, startOfNationalNumber)]]; + } + } + + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + [self.nationalNumber_ appendString:[nationalNumber substringFromIndex:startOfNationalNumber]]; + return [nationalNumber substringWithRange:NSMakeRange(0, startOfNationalNumber)]; +}; + + +/** + * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are + * available, and places the remaining input into nationalNumber. + * + * @return {BOOL} YES when accruedInputWithoutFormatting begins with the + * plus sign or valid IDD for defaultCountry. + * @private + */ +- (BOOL)attemptToExtractIdd_ +{ + /** @type {string} */ + NSString *accruedInputWithoutFormatting = [self.accruedInputWithoutFormatting_ copy]; + /** @type {RegExp} */ + NSString *internationalPrefix = [NSString stringWithFormat:@"^(?:\\+|%@)", self.currentMetaData_.internationalPrefix]; + /** @type {Array.} */ + NSArray *m = [self.phoneUtil_ matchedStringByRegex:accruedInputWithoutFormatting regex:internationalPrefix]; + + NSString *firstString = [m safeObjectAtIndex:0]; + + if (m != nil && firstString != nil && firstString.length > 0) { + self.isCompleteNumber_ = YES; + /** @type {number} */ + unsigned int startOfCountryCallingCode = (unsigned int)firstString.length; + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + [self.nationalNumber_ appendString:[accruedInputWithoutFormatting substringFromIndex:startOfCountryCallingCode]]; + self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""]; + [self.prefixBeforeNationalNumber_ appendString:[accruedInputWithoutFormatting substringWithRange:NSMakeRange(0, startOfCountryCallingCode)]]; + + if ([accruedInputWithoutFormatting characterAtIndex:0] != '+') + { + [self.prefixBeforeNationalNumber_ appendString:[NSString stringWithFormat: @"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]]; + } + return YES; + } + return NO; +}; + + +/** + * Extracts the country calling code from the beginning of nationalNumber to + * prefixBeforeNationalNumber when they are available, and places the remaining + * input into nationalNumber. + * + * @return {BOOL} YES when a valid country calling code can be found. + * @private + */ +- (BOOL)attemptToExtractCountryCallingCode_ +{ + if (self.nationalNumber_.length == 0) { + return NO; + } + + /** @type {!goog.string.StringBuffer} */ + NSString *numberWithoutCountryCallingCode = @""; + + /** @type {number} */ + NSNumber *countryCode = [self.phoneUtil_ extractCountryCode:self.nationalNumber_ nationalNumber:&numberWithoutCountryCallingCode]; + + if ([countryCode isEqualToNumber:@0]) { + return NO; + } + + self.nationalNumber_ = [NSMutableString stringWithString:@""]; + [self.nationalNumber_ appendString:numberWithoutCountryCallingCode]; + + /** @type {string} */ + NSString *newRegionCode = [self.phoneUtil_ getRegionCodeForCountryCode:countryCode]; + + if ([NB_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:newRegionCode]) { + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + self.currentMetaData_ = [helper getMetadataForNonGeographicalRegion:countryCode]; + } else if (newRegionCode != self.defaultCountry_) { + self.currentMetaData_ = [self getMetadataForRegion_:newRegionCode]; + } + + /** @type {string} */ + NSString *countryCodeString = [NSString stringWithFormat:@"%@", countryCode]; + [self.prefixBeforeNationalNumber_ appendString:countryCodeString]; + [self.prefixBeforeNationalNumber_ appendString:[NSString stringWithFormat: @"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]]; + return YES; +}; + + +/** + * Accrues digits and the plus sign to accruedInputWithoutFormatting for later + * use. If nextChar contains a digit in non-ASCII format (e.g. the full-width + * version of digits), it is first normalized to the ASCII version. The return + * value is nextChar itself, or its normalized version, if nextChar is a digit + * in non-ASCII format. This method assumes its input is either a digit or the + * plus sign. + * + * @param {string} nextChar + * @param {BOOL} rememberPosition + * @return {string} + * @private + */ +- (NSString*)normalizeAndAccrueDigitsAndPlusSign_:(NSString *)nextChar rememberPosition:(BOOL)rememberPosition +{ + /** @type {string} */ + NSString *normalizedChar; + + if ([nextChar isEqualToString:@"+"]) { + normalizedChar = nextChar; + [self.accruedInputWithoutFormatting_ appendString:nextChar]; + } else { + normalizedChar = [[self.phoneUtil_ DIGIT_MAPPINGS] objectForKey:nextChar]; + if (!normalizedChar) return @""; + + [self.accruedInputWithoutFormatting_ appendString:normalizedChar]; + [self.nationalNumber_ appendString:normalizedChar]; + } + + if (rememberPosition) { + self.positionToRemember_ = self.accruedInputWithoutFormatting_.length; + } + + return normalizedChar; +}; + + +/** + * @param {string} nextChar + * @return {string} + * @private + */ +- (NSString*)inputDigitHelper_:(NSString *)nextChar +{ + /** @type {string} */ + NSString *formattingTemplate = [self.formattingTemplate_ copy]; + NSString *subedString = @""; + + if (formattingTemplate.length > self.lastMatchPosition_) { + subedString = [formattingTemplate substringFromIndex:self.lastMatchPosition_]; + } + + if ([self.phoneUtil_ stringPositionByRegex:subedString regex:self.DIGIT_PLACEHOLDER_] >= 0) { + /** @type {number} */ + int digitPatternStart = [self.phoneUtil_ stringPositionByRegex:formattingTemplate regex:self.DIGIT_PLACEHOLDER_]; + + /** @type {string} */ + NSRange tempRange = [formattingTemplate rangeOfString:self.DIGIT_PLACEHOLDER_]; + NSString *tempTemplate = [formattingTemplate stringByReplacingOccurrencesOfString:self.DIGIT_PLACEHOLDER_ + withString:nextChar + options:NSLiteralSearch + range:tempRange]; + self.formattingTemplate_ = [NSMutableString stringWithString:@""]; + [self.formattingTemplate_ appendString:tempTemplate]; + self.lastMatchPosition_ = digitPatternStart; + return [tempTemplate substringWithRange:NSMakeRange(0, self.lastMatchPosition_ + 1)]; + } else { + if (self.possibleFormats_.count == 1) + { + // More digits are entered than we could handle, and there are no other + // valid patterns to try. + self.ableToFormat_ = NO; + } // else, we just reset the formatting pattern. + self.currentFormattingPattern_ = @""; + return self.accruedInput_; + } +}; + + +/** + * Returns the formatted number. + * + * @return {string} + */ +- (NSString *)description +{ + return self.currentOutput_; +} + +- (NSString *)regionPrefix { + return self.prefixBeforeNationalNumber_; +} + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.h new file mode 100644 index 0000000000..240fcf50cd --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.h @@ -0,0 +1,764 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import +#import "NBPhoneMetaData.h" + +@interface NBPhoneMetadataIM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataHR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataHT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataHU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIQ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataJM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataJO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataJP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLI : NBPhoneMetaData +@end + +@interface NBPhoneMetadata881 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataME : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLK : NBPhoneMetaData +@end + +@interface NBPhoneMetadata882 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMH : NBPhoneMetaData +@end + +@interface NBPhoneMetadata883 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataML : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataKZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMQ : NBPhoneMetaData +@end + +@interface NBPhoneMetadata888 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLV : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataQA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataLY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMV : NBPhoneMetaData +@end + +@interface NBPhoneMetadataOM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataMZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataRE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataNZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSJ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataUA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataRO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataPY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataRS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTJ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataUG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataRU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVC : NBPhoneMetaData +@end + +@interface NBPhoneMetadata870 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataRW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataST : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSV : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataWF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataSZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTV : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataUS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadata878 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataYE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataZA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataUY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataVU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataUZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataWS : NBPhoneMetaData +@end + +@interface NBPhoneMetadata979 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataZM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataYT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataZW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBJ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBL : NBPhoneMetaData +@end + +@interface NBPhoneMetadata800 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataEC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBQ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataEE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDJ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataEG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataAZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataEH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataBZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCV : NBPhoneMetaData +@end + +@interface NBPhoneMetadata808 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCW : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFJ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGF : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataCZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGH : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataER : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGI : NBPhoneMetaData +@end + +@interface NBPhoneMetadataES : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataET : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataDZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGM : NBPhoneMetaData +@end + +@interface NBPhoneMetadataID : NBPhoneMetaData +@end + +@interface NBPhoneMetadataFR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataHK : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGQ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataHN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataJE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataGU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataIL : NBPhoneMetaData +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.m new file mode 100644 index 0000000000..efc4dc13cb --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCore.m @@ -0,0 +1,14237 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import "NBMetadataCore.h" +#import "NBPhoneNumberDefines.h" +#import "NBPhoneNumberDesc.h" + +#import "NBNumberFormat.h" + +@implementation NBPhoneMetadataIM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[135789]\\d{6,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1624\\d{6}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1624456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[569]24\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7924123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"808162\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8081624567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:872299|90[0167]624)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9016247890"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:4(?:40[49]06|5624\\d)|70624\\d)\\d{3}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8456247890"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"56\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5612345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:08162\\d|3\\d{5}|4(?:40[49]06|5624\\d)|7(?:0624\\d|2299\\d))\\d{3}|55\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IM"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" x"; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataHR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{5,8}|[89]\\d{6,11}" withPossibleNumberPattern:@"\\d{6,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{7}|(?:2[0-3]|3[1-5]|4[02-47-9]|5[1-3])\\d{6,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:[1-9]\\d{6,10}|01\\d{6,9})" withPossibleNumberPattern:@"\\d{8,12}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[01]\\d{4,7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:[01459]\\d{4,7})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"611234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[45]\\d{4,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"741234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[76]2\\d{6,7}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"62123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"HR"; + self.countryCode = [NSNumber numberWithInteger:385]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6[09]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(6[09])(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[67]2"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([67]2)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[2-5]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([2-5]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d)(\\d{3,4})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"6[0145]|7"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"6[0145]|7"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(80[01])(\\d{2})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(80[01])(\\d{3,4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4(?:0\\d{5}|4\\d{7})|9\\d{8})" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"443(?:2[0125]|3[1245]|4[12]|5[1-4]|70|9[1-467])\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"443201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:55\\d|6(?:6\\d|9[012])|77\\d)\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"955012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"40\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"4012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GW"; + self.countryCode = [NSNumber numberWithInteger:245]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"44|9[567]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"40"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{7,12}|[2-9]\\d{9,10}" withPossibleNumberPattern:@"\\d{6,13}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:11|2[02]|33|4[04]|79)[2-7]\\d{7}|80[2-467]\\d{7}|(?:1(?:2[0-249]|3[0-25]|4[145]|[59][14]|6[014]|7[1257]|8[01346])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|[36][25]|22|4[28]|5[12]|[78]1|9[15])|6(?:12|[2345]1|57|6[13]|7[14]|80)|7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1|88)|8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91))[2-7]\\d{6}|(?:(?:1(?:2[35-8]|3[346-9]|4[236-9]|[59][0235-9]|6[235-9]|7[34689]|8[257-9])|2(?:1[134689]|3[24-8]|4[2-8]|5[25689]|6[2-4679]|7[13-79]|8[2-479]|9[235-9])|3(?:01|1[79]|2[1-5]|4[25-8]|5[125689]|6[235-7]|7[157-9]|8[2-467])|4(?:1[14578]|2[5689]|3[2-467]|5[4-7]|6[35]|73|8[2689]|9[2389])|5(?:[16][146-9]|2[14-8]|3[1346]|4[14-69]|5[46]|7[2-4]|8[2-8]|9[246])|6(?:1[1358]|2[2457]|3[2-4]|4[235-7]|[57][2-689]|6[24-578]|8[1-6])|8(?:1[1357-9]|2[235-8]|3[03-57-9]|4[0-24-9]|5\\d|6[2457-9]|7[1-6]|8[1256]|9[2-4]))\\d|7(?:(?:1[013-9]|2[0235-9]|3[2679]|4[1-35689]|5[2-46-9]|[67][02-9]|9\\d)\\d|8(?:2[0-6]|[013-8]\\d)))[2-7]\\d{5}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:7(?:0\\d{3}|2(?:[0235679]\\d{2}|[14][017-9]\\d|8(?:[0-59]\\d|6[089])|9[389]\\d)|3(?:[05-8]\\d{2}|1(?:[089]\\d|7[5-8])|2(?:[5-8]\\d|[01][089])|3[17-9]\\d|4(?:[07-9]\\d|11)|9(?:[01689]\\d|59))|4(?:0[1-9]\\d|1(?:[015-9]\\d|4[08])|2(?:[1-7][089]|[89]\\d)|3(?:[0-8][089]|9\\d)|4(?:[089]\\d|11|7[02-8])|5(?:0[089]|99)|7(?:0[3-9]|11|7[02-8]|[89]\\d)|8(?:[0-24-7][089]|[389]\\d)|9(?:[0-6][089]|7[08]|[89]\\d))|5(?:[034678]\\d|2[03-9]|5[017-9]|9[7-9])\\d|6(?:0[0-47]|1[0-257-9]|2[0-4]|3[19]|5[4589]|[6-9]\\d)\\d|7(?:0[2-9]|[1-79]\\d|8[1-9])\\d|8(?:[0-79]\\d{2}|880)|99[4-9]\\d)|8(?:0(?:[01589]\\d|6[67])|1(?:[02-57-9]\\d|1[0135-9])|2(?:[236-9]\\d|5[1-9])|3(?:[0357-9]\\d|4[1-9])|[45]\\d{2}|6[02457-9]\\d|7(?:07|[1-69]\\d)|8(?:[0-26-9]\\d|44|5[2-9])|9(?:[035-9]\\d|2[2-9]|4[0-8]))\\d|9\\d{4})\\d{5}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9987654321"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:600\\d{6}|80(?:0\\d{4,9}|3\\d{9}))" withPossibleNumberPattern:@"\\d{8,13}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"186[12]\\d{9}" withPossibleNumberPattern:@"\\d{13}" withExample:@"1861123456789"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1860\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"18603451234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"140\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1409305260"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:600\\d{6}|8(?:0(?:0\\d{4,9}|3\\d{9})|6(?:0\\d{7}|[12]\\d{9})))" withPossibleNumberPattern:@"\\d{8,13}" withExample:@"1800123456"]; + self.codeID = @"IN"; + self.countryCode = [NSNumber numberWithInteger:91]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"7(?:[023578]|4[0-57-9]|6[0-35-9]|99)|8(?:0[015689]|1[0-57-9]|2[2356-9]|3[0-57-9]|[45]|6[02457-9]|7[01-69]|8[0-24-9]|9[02-9])|9"]; + [numberFormats0_patternArray addObject:@"7(?:[08]|2(?:[0235679]|[14][017-9]|8[0-569]|9[389])|3(?:[05-8]|1[07-9]|2[015-8]|3[17-9]|4[017-9]|9[015689])|4(?:[02][1-9]|1[014-9]|3\\d|[47][017-9]|5[09]|[89])|5(?:[034678]|2[03-9]|5[017-9]|9[7-9])|6(?:0[0-47]|1[0-257-9]|2[0-4]|3[19]|5[4589]|[6-9])|7(?:0[2-9]|[1-79]|8[1-9])|99[4-9])|8(?:0(?:[01589]|6[67])|1(?:[02-57-9]|1[0135-9])|2(?:[236-9]|5[1-9])|3(?:[0357-9]|4[1-9])|[45]|6[02457-9]|7(?:07|[1-69])|8(?:[0-26-9]|44|5[2-9])|9(?:[035-9]|2[2-9]|4[0-8]))|9"]; + [numberFormats0_patternArray addObject:@"7(?:0|2(?:[0235679]|[14][017-9]|8[0-569]|9[389])|3(?:[05-8]|1(?:[089]|7[5-9])|2(?:[5-8]|[01][089])|3[17-9]|4(?:[07-9]|11)|9(?:[01689]|59))|4(?:0[1-9]|1(?:[015-9]|4[08])|2(?:[1-7][089]|[89])|3(?:[0-8][089]|9)|4(?:[089]|11|7[02-8])|5(?:0[089]|99)|7(?:0[3-9]|11|7[02-8]|[89])|8(?:[0-24-7][089]|[389])|9(?:[0-6][089]|7[08]|[89]))|5(?:[034678]|2[03-9]|5[017-9]|9[7-9])|6(?:0[0-47]|1[0-257-9]|2[0-4]|3[19]|5[4589]|[6-9])|7(?:0[2-9]|[1-79]|8[1-9])|8(?:[0-79]|880)|99[4-9])|8(?:0(?:[01589]|6[67])|1(?:[02-57-9]|1[0135-9])|2(?:[236-9]|5[1-9])|3(?:[0357-9]|4[1-9])|[45]|6[02457-9]|7(?:07|[1-69])|8(?:[0-26-9]|44|5[2-9])|9(?:[035-9]|2[2-9]|4[0-8]))|9"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"11|2[02]|33|4[04]|79|80[2-46]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:2[0-249]|3[0-25]|4[145]|[569][14]|7[1257]|8[1346]|[68][1-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|[36][25]|22|4[28]|5[12]|[78]1|9[15])|6(?:12|[2345]1|57|6[13]|7[14]|80)"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1|88)"]; + [numberFormats3_patternArray addObject:@"7(?:12|2[14]|3[134]|4[47]|5(?:1|5[2-6])|[67]1|88)"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"1(?:[23579]|[468][1-9])|[2-8]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"160"]; + [numberFormats6_patternArray addObject:@"1600"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(1600)(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"180"]; + [numberFormats7_patternArray addObject:@"1800"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(1800)(\\d{4,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"18[06]"]; + [numberFormats8_patternArray addObject:@"18[06]0"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(18[06]0)(\\d{2,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"140"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(140)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"18[06]"]; + [numberFormats10_patternArray addObject:@"18(?:0[03]|6[12])"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20\\d{6,7}|[4-9]\\d{6,9}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20\\d{6,7}|4(?:[0136]\\d{7}|[245]\\d{5,7})|5(?:[08]\\d{7}|[1-79]\\d{5,7})|6(?:[01457-9]\\d{5,7}|[26]\\d{7})" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"202012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[0-36]\\d|5[0-6]|[79][0-7]|8[0-25-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"712123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800[24-8]\\d{5,6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"800223456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[02-9]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900223456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KE"; + self.countryCode = [NSNumber numberWithInteger:254]; + self.internationalPrefix = @"000"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"005|0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[24-6]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{7,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[13]|3(?:0\\d|[14])|[5-7][14]|41|8[1468])\\d{6}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"21212862"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20(?:2[2389]|5[4-689]|7[6-8]|9[15-9])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2023123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LA"; + self.countryCode = [NSNumber numberWithInteger:856]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"20"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(20)(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[13]|3[14]|[4-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([2-8]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"30"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(30)(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"37\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3709100"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"38\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3801234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IO"; + self.countryCode = [NSNumber numberWithInteger:246]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataHT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-489]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[248]\\d|5[1-5]|94)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22453300"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[1-9]\\d|4\\d{2}|9(?:8[0-35]|9[5-9]))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"34101234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"98[89]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"98901234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"HT"; + self.countryCode = [NSNumber numberWithInteger:509]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-4679]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:1[6-9]|2[0-35-9]|3[1-4]|5[3-9]|6\\d|7[0-24-79])|3(?:2[25-9]|3\\d)|4(?:4[0-24]|5[56])|77[1-57])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6091234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:289|862)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2891234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9008\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9008123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GY"; + self.countryCode = [NSNumber numberWithInteger:592]; + self.internationalPrefix = @"001"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13-9]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[14-6]\\d{2}|7(?:[2-57]\\d|62|8[0-7]|9[04-9])|8[02-9]\\d|9\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"1123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3\\d|7(?:[01]\\d|6[013-9]|8[89]|9[1-3])|81\\d)\\d{5}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"71123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[01]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LB"; + self.countryCode = [NSNumber numberWithInteger:961]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[13-6]|7(?:[2-57]|62|8[0-7]|9[04-9])|8[02-9]|9"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[89][01]|7(?:[01]|6[013-9]|8[89]|9[1-3])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([7-9]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235-8]\\d{8,9}" withPossibleNumberPattern:@"\\d{5,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:1(?:[256]\\d|3[1-9]|47)|2(?:22|3[0-479]|6[0-7])|4(?:22|5[6-9]|6\\d)|5(?:22|3[4-7]|59|6\\d)|6(?:22|5[35-7]|6\\d)|7(?:22|3[468]|4[1-9]|59|[67]\\d)|9(?:22|4[1-8]|6\\d))|6(?:09|12|2[2-4])\\d)\\d{5}" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"312123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:20[0-35]|5[124-7]\\d|7[07]\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"700123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6,7}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KG"; + self.countryCode = [NSNumber numberWithInteger:996]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[25-7]|31[25]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3(?:1[36]|[2-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d)(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataHU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1\\d|2(?:1\\d|[2-9])|3(?:[2-7]|8\\d)|4[24-9]|5[2-79]|6[23689]|7(?:1\\d|[2-9])|8[2-57-9]|9[2-69])\\d{6}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[257]0|3[01])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"201234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[01]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"40\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"40123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[48]0\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.codeID = @"HU"; + self.countryCode = [NSNumber numberWithInteger:36]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"06"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"06"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5789]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"758(?:4(?:30|5[0-9]|6[2-9]|8[0-2])|57[0-2]|638)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7584305678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"758(?:28[4-7]|384|4(?:6[01]|8[4-9])|5(?:1[89]|20|84)|7(?:1[2-9]|2[0-8]))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7582845678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LC"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"758"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIQ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{7,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{7}|(?:2[13-5]|3[02367]|4[023]|5[03]|6[026])\\d{6,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[3-9]\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IQ"; + self.countryCode = [NSNumber numberWithInteger:964]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-6]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([2-6]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{7,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[3-6]|3[2-6]|4[2-4]|[5-7][2-5])(?:[237-9]|4[56]|5\\d|6\\d?)\\d{5}|23(?:4[234]|8\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"23756789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:[013-79]\\d|[28]\\d{1,2})|2[3-6]48|3(?:[18]\\d{2}|[2-6]48)|4[2-4]48|5[2-5]48|6(?:[016-9]\\d|[2-5]48)|7(?:[07-9]\\d|[16]\\d{2}|[2-5]48)|8(?:[013-79]\\d|8\\d{2})|9(?:6\\d{2}|7\\d{1,2}|[0-589]\\d))\\d{5}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"91234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800(?:1\\d|2[019])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1900(?:1\\d|2[09])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KH"; + self.countryCode = [NSNumber numberWithInteger:855]; + self.internationalPrefix = @"00[14-9]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1\\d[1-9]|[2-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[89]0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(1[89]00)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataJM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"876(?:5(?:0[12]|1[0-468]|2[35]|63)|6(?:0[1-3579]|1[027-9]|[23]\\d|40|5[06]|6[2-589]|7[05]|8[04]|9[4-9])|7(?:0[2-689]|[1-6]\\d|8[056]|9[45])|9(?:0[1-8]|1[02378]|[2-8]\\d|9[2-468]))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8765123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"876(?:2[16-9]\\d|[348]\\d{2}|5(?:0[3-9]|27|6[0-24-9]|[3-578]\\d)|7(?:0[07]|7\\d|8[1-47-9]|9[0-36-9])|9(?:[01]9|9[0579]))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8762101234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"JM"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"876"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-8]\\d{9}|9(?:[0-4]\\d{8}|9\\d{2,8})" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[137]|2[13-68]|3[1458]|4[145]|5[146-8]|6[146]|7[1467]|8[13467])\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:0[1-3]|[13]\\d|2[0-2]|90)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-6]0\\d|993)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9932123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"943\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9432123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9990\\d{0,6}" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"9990123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IR"; + self.countryCode = [NSNumber numberWithInteger:98]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"21"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(21)(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[1-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2458]\\d{4}|3\\d{4,7}|7\\d{7}" withPossibleNumberPattern:@"\\d{5,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[24]\\d|3[1-9]|50|8[0-5])\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"31234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"72012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3001\\d{4}" withPossibleNumberPattern:@"\\d{5,8}" withExample:@"30010000"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KI"; + self.countryCode = [NSNumber numberWithInteger:686]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[4-9]\\d{6}|38\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4(?:1[0-24-6]|2[0-7]|[37][0-8]|4[0-245]|5[0-68]|6\\d|8[0-36-8])|5(?:05|[156]\\d|2[02578]|3[013-79]|4[03-7]|7[0-2578]|8[0-35-9]|9[013-689])|87[23])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4101234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"38[589]\\d{6}|(?:6(?:1[1-8]|2[056]|3[089]|4[0167]|5[0159]|[67][0-69]|9\\d)|7(?:5[057]|6[0-2]|[78]\\d)|8(?:2[0-59]|3[0-4]|[469]\\d|5[1-9]))\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"6111234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9011234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"49\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4921234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"809\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8091234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6(?:2[1-478]|49|8\\d)|8(?:7[0189]|80)|95[48])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6211234"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IS"; + self.countryCode = [NSNumber numberWithInteger:354]; + self.internationalPrefix = @"1(?:0(?:01|10|20)|100)|00"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[4-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(3\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:2(?:(?:[015-7]\\d|2[02-9]|3[2-57]|4[2-8]|8[235-7])\\d|9(?:0\\d|[89]0))|3(?:(?:[0-4]\\d|[57][2-9]|6[235-8]|9[3-9])\\d|8(?:0\\d|[89]0)))\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"520123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:0[0-8]|[12-79]\\d|8[017])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"650123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"891234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MA"; + self.countryCode = [NSNumber numberWithInteger:212]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"5(?:2[015-7]|3[0-4])|6"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([56]\\d{2})(\\d{6})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"5(?:2[2-489]|3[5-9])|892"]; + [numberFormats1_patternArray addObject:@"5(?:2(?:[2-48]|90)|3(?:[5-79]|80))|892"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([58]\\d{3})(\\d{5})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"5(?:29|38)"]; + [numberFormats2_patternArray addObject:@"5(?:29|38)[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8(?:0|9[013-9])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(8[09])(\\d{7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataJO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:6(?:2[0-35-9]|3[0-57-8]|4[24-7]|5[0-24-8]|[6-8][023]|9[0-3])|7(?:0[1-79]|10|2[014-7]|3[0-689]|4[019]|5[0-3578]))|32(?:0[1-69]|1[1-35-7]|2[024-7]|3\\d|4[0-3]|[57][023]|6[03])|53(?:0[0-3]|[13][023]|2[0-59]|49|5[0-35-9]|6[15]|7[45]|8[1-6]|9[0-36-9])|6(?:2[50]0|3(?:00|33)|4(?:0[0125]|1[2-7]|2[0569]|[38][07-9]|4[025689]|6[0-589]|7\\d|9[0-2])|5(?:[01][056]|2[034]|3[0-57-9]|4[17-8]|5[0-69]|6[0-35-9]|7[1-379]|8[0-68]|9[02-39]))|87(?:[02]0|7[08]|90))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"62001234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:55|7[025-9]|8[015-9]|9[0-25-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"790123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"85\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"85012345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"700123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"74(?:66|77)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"746612345"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:10|8\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88101234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"JO"; + self.countryCode = [NSNumber numberWithInteger:962]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2356]|87"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7[457-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"70|8[0158]|9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[01589]\\d{5,10}|3(?:[12457-9]\\d{8}|[36]\\d{7,9})" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0(?:[26]\\d{4,9}|(?:1(?:[0159]\\d|[27][1-5]|31|4[1-4]|6[1356]|8[2-57])|3(?:[0159]\\d|2[1-4]|3[12]|[48][1-6]|6[2-59]|7[1-7])|4(?:[0159]\\d|[23][1-9]|4[245]|6[1-5]|7[1-4]|81)|5(?:[0159]\\d|2[1-5]|3[2-6]|4[1-79]|6[4-6]|7[1-578]|8[3-8])|7(?:[0159]\\d|2[12]|3[1-7]|4[2346]|6[13569]|7[13-6]|8[1-59])|8(?:[0159]\\d|2[34578]|3[1-356]|[6-8][1-5])|9(?:[0159]\\d|[238][1-5]|4[12]|6[1-8]|7[1-6]))\\d{2,7})" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"0212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:[12457-9]\\d{8}|6\\d{7,8}|3\\d{7,9})" withPossibleNumberPattern:@"\\d{9,11}" withExample:@"3123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:0\\d{6}|3\\d{3})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0878\\d{5}|1(?:44|6[346])\\d{6}|89(?:2\\d{3}|4(?:[0-4]\\d{2}|[5-9]\\d{4})|5(?:[0-4]\\d{2}|[5-9]\\d{6})|9\\d{6})" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"899123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"84(?:[08]\\d{6}|[17]\\d{3})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"848123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:78\\d|99)\\d{6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"1781234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"55\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"848\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"848123456"]; + self.codeID = @"IT"; + self.countryCode = [NSNumber numberWithInteger:39]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"0[26]|55"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0[26]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(0[26])(\\d{4})(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"0[26]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(0[26])(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"0[13-57-9][0159]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(0\\d{2})(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"0[13-57-9][0159]|8(?:03|4[17]|9[245])"]; + [numberFormats4_patternArray addObject:@"0[13-57-9][0159]|8(?:03|4[17]|9(?:2|[45][0-4]))"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"0[13-57-9][2-46-8]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(0\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"0[13-57-9][2-46-8]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(0\\d{3})(\\d{2,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"[13]|8(?:00|4[08]|9[59])"]; + [numberFormats7_patternArray addObject:@"[13]|8(?:00|4[08]|9(?:5[5-9]|9))"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"894"]; + [numberFormats8_patternArray addObject:@"894[5-9]"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataJP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8,9}|00(?:[36]\\d{7,14}|7\\d{5,7}|8\\d{7})" withPossibleNumberPattern:@"\\d{8,17}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:1[235-8]|2[3-6]|3[3-9]|4[2-6]|[58][2-8]|6[2-7]|7[2-9]|9[1-9])|2[2-9]\\d|[36][1-9]\\d|4(?:6[02-8]|[2-578]\\d|9[2-59])|5(?:6[1-9]|7[2-8]|[2-589]\\d)|7(?:3[4-9]|4[02-9]|[25-9]\\d)|8(?:3[2-9]|4[5-9]|5[1-9]|8[03-9]|[2679]\\d)|9(?:[679][1-9]|[2-58]\\d))\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"312345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[7-9]0[1-9]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9012345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"120\\d{6}|800\\d{7}|00(?:37\\d{6,13}|66\\d{6,13}|777(?:[01]\\d{2}|5\\d{3}|8\\d{4})|882[1245]\\d{4})" withPossibleNumberPattern:@"\\d{8,17}" withExample:@"120123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"990\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"990123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"601234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"50[1-9]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5012345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2012345678"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"570\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"570123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"00(?:37\\d{6,13}|66\\d{6,13}|777(?:[01]\\d{2}|5\\d{3}|8\\d{4})|882[1245]\\d{4})" withPossibleNumberPattern:@"\\d{8,17}" withExample:@"00777012"]; + self.codeID = @"JP"; + self.countryCode = [NSNumber numberWithInteger:81]; + self.internationalPrefix = @"010"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:12|57|99)0"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"0077"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"0077"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{3,4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"0088"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"00(?:37|66)"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3,4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"00(?:37|66)"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})(\\d{4,5})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"00(?:37|66)"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{5})(\\d{5,6})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"00(?:37|66)"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{6})(\\d{6,7})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"[2579]0|80[1-9]"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|5(?:76|97)|499|746|8(?:3[89]|63|47|51)|9(?:49|80|9[16])"]; + [numberFormats10_patternArray addObject:@"1(?:267|3(?:7[247]|9[278])|4(?:5[67]|66)|5(?:47|58|64|8[67])|6(?:3[245]|48|5[4-68]))|5(?:76|97)9|499[2468]|7468|8(?:3(?:8[78]|96)|636|477|51[24])|9(?:496|802|9(?:1[23]|69))"]; + [numberFormats10_patternArray addObject:@"1(?:267|3(?:7[247]|9[278])|4(?:5[67]|66)|5(?:47|58|64|8[67])|6(?:3[245]|48|5[4-68]))|5(?:769|979[2-69])|499[2468]|7468|8(?:3(?:8[78]|96[2457-9])|636[2-57-9]|477|51[24])|9(?:496|802|9(?:1[23]|69))"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d)(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + + NSMutableArray *numberFormats11_patternArray = [[NSMutableArray alloc] init]; + [numberFormats11_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5[2-8]|[68][2-7]|7[2-689]|9[1-578])|2(?:2[03-689]|3[3-58]|4[0-468]|5[04-8]|6[013-8]|7[06-9]|8[02-57-9]|9[13])|4(?:2[28]|3[689]|6[035-7]|7[05689]|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9[4-9])|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9[014-9])|8(?:2[49]|3[3-8]|4[5-8]|5[2-9]|6[35-9]|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9[3-7])"]; + [numberFormats11_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9[2-8])|3(?:7[2-6]|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5[4-7]|6[2-9]|8[2-8]|9[236-9])|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3[34]|[4-7]))"]; + [numberFormats11_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9(?:[3578]|20|4[04-9]|6[56]))|3(?:7(?:[2-5]|6[0-59])|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5(?:[467]|5[014-9])|6(?:[2-8]|9[02-69])|8[2-8]|9(?:[236-8]|9[23]))|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3(?:3[02-9]|4[0-24689])|4[2-69]|[5-7]))"]; + [numberFormats11_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9(?:[3578]|20|4[04-9]|6(?:5[25]|60)))|3(?:7(?:[2-5]|6[0-59])|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5(?:[467]|5[014-9])|6(?:[2-8]|9[02-69])|8[2-8]|9(?:[236-8]|9[23]))|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3(?:3[02-9]|4[0-24689])|4[2-69]|[5-7]))"]; + NBNumberFormat *numberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats11_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats11]; + + NSMutableArray *numberFormats12_patternArray = [[NSMutableArray alloc] init]; + [numberFormats12_patternArray addObject:@"1|2(?:2[37]|5[5-9]|64|78|8[39]|91)|4(?:2[2689]|64|7[347])|5(?:[2-589]|39)|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93)"]; + [numberFormats12_patternArray addObject:@"1|2(?:2[37]|5(?:[57]|[68]0|9[19])|64|78|8[39]|917)|4(?:2(?:[68]|20|9[178])|64|7[347])|5(?:[2-589]|39[67])|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93[34])"]; + [numberFormats12_patternArray addObject:@"1|2(?:2[37]|5(?:[57]|[68]0|9(?:17|99))|64|78|8[39]|917)|4(?:2(?:[68]|20|9[178])|64|7[347])|5(?:[2-589]|39[67])|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93(?:31|4))"]; + NBNumberFormat *numberFormats12 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats12_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats12]; + + NSMutableArray *numberFormats13_patternArray = [[NSMutableArray alloc] init]; + [numberFormats13_patternArray addObject:@"2(?:9[14-79]|74|[34]7|[56]9)|82|993"]; + NBNumberFormat *numberFormats13 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats13_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats13]; + + NSMutableArray *numberFormats14_patternArray = [[NSMutableArray alloc] init]; + [numberFormats14_patternArray addObject:@"3|4(?:2[09]|7[01])|6[1-9]"]; + NBNumberFormat *numberFormats14 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats14_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats14]; + + NSMutableArray *numberFormats15_patternArray = [[NSMutableArray alloc] init]; + [numberFormats15_patternArray addObject:@"[2479][1-9]"]; + NBNumberFormat *numberFormats15 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats15_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats15]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"(?:12|57|99)0"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"800"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"[2579]0|80[1-9]"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|5(?:76|97)|499|746|8(?:3[89]|63|47|51)|9(?:49|80|9[16])"]; + [intlNumberFormats3_patternArray addObject:@"1(?:267|3(?:7[247]|9[278])|4(?:5[67]|66)|5(?:47|58|64|8[67])|6(?:3[245]|48|5[4-68]))|5(?:76|97)9|499[2468]|7468|8(?:3(?:8[78]|96)|636|477|51[24])|9(?:496|802|9(?:1[23]|69))"]; + [intlNumberFormats3_patternArray addObject:@"1(?:267|3(?:7[247]|9[278])|4(?:5[67]|66)|5(?:47|58|64|8[67])|6(?:3[245]|48|5[4-68]))|5(?:769|979[2-69])|499[2468]|7468|8(?:3(?:8[78]|96[2457-9])|636[2-57-9]|477|51[24])|9(?:496|802|9(?:1[23]|69))"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d)(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5[2-8]|[68][2-7]|7[2-689]|9[1-578])|2(?:2[03-689]|3[3-58]|4[0-468]|5[04-8]|6[013-8]|7[06-9]|8[02-57-9]|9[13])|4(?:2[28]|3[689]|6[035-7]|7[05689]|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9[4-9])|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9[014-9])|8(?:2[49]|3[3-8]|4[5-8]|5[2-9]|6[35-9]|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9[3-7])"]; + [intlNumberFormats4_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9[2-8])|3(?:7[2-6]|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5[4-7]|6[2-9]|8[2-8]|9[236-9])|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3[34]|[4-7]))"]; + [intlNumberFormats4_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9(?:[3578]|20|4[04-9]|6[56]))|3(?:7(?:[2-5]|6[0-59])|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5(?:[467]|5[014-9])|6(?:[2-8]|9[02-69])|8[2-8]|9(?:[236-8]|9[23]))|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3(?:3[02-9]|4[0-24689])|4[2-69]|[5-7]))"]; + [intlNumberFormats4_patternArray addObject:@"1(?:2[3-6]|3[3-9]|4[2-6]|5(?:[236-8]|[45][2-69])|[68][2-7]|7[2-689]|9[1-578])|2(?:2(?:[04-689]|3[23])|3[3-58]|4[0-468]|5(?:5[78]|7[2-4]|[0468][2-9])|6(?:[0135-8]|4[2-5])|7(?:[0679]|8[2-7])|8(?:[024578]|3[25-9]|9[6-9])|9(?:11|3[2-4]))|4(?:2(?:2[2-9]|8[237-9])|3[689]|6[035-7]|7(?:[059][2-8]|[68])|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9(?:[89][2-8]|[4-7]))|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9(?:[017-9]|4[6-8]|5[2-478]|6[2-589]))|8(?:2(?:4[4-8]|9(?:[3578]|20|4[04-9]|6(?:5[25]|60)))|3(?:7(?:[2-5]|6[0-59])|[3-6][2-9]|8[2-5])|4[5-8]|5[2-9]|6(?:[37]|5(?:[467]|5[014-9])|6(?:[2-8]|9[02-69])|8[2-8]|9(?:[236-8]|9[23]))|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9(?:3(?:3[02-9]|4[0-24689])|4[2-69]|[5-7]))"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"1|2(?:2[37]|5[5-9]|64|78|8[39]|91)|4(?:2[2689]|64|7[347])|5(?:[2-589]|39)|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93)"]; + [intlNumberFormats5_patternArray addObject:@"1|2(?:2[37]|5(?:[57]|[68]0|9[19])|64|78|8[39]|917)|4(?:2(?:[68]|20|9[178])|64|7[347])|5(?:[2-589]|39[67])|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93[34])"]; + [intlNumberFormats5_patternArray addObject:@"1|2(?:2[37]|5(?:[57]|[68]0|9(?:17|99))|64|78|8[39]|917)|4(?:2(?:[68]|20|9[178])|64|7[347])|5(?:[2-589]|39[67])|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93(?:31|4))"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"2(?:9[14-79]|74|[34]7|[56]9)|82|993"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + + NSMutableArray *intlNumberFormats7_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats7_patternArray addObject:@"3|4(?:2[09]|7[01])|6[1-9]"]; + NBNumberFormat *intlNumberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats7]; + + NSMutableArray *intlNumberFormats8_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats8_patternArray addObject:@"[2479][1-9]"]; + NBNumberFormat *intlNumberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats8]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataMC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[4689]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"870\\d{5}|9[2-47-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"99123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{8}|4(?:4\\d|5[1-9])\\d{5}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"612345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.codeID = @"MC"; + self.countryCode = [NSNumber numberWithInteger:377]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"4"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(6)(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[379]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:6[0-37-9]|7[0-57-9])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7712345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[234]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3212345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:39[01]|9[01]0)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9001234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KM"; + self.countryCode = [NSNumber numberWithInteger:269]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:1[0569]|2\\d|3[015-7]|4[1-46-9]|5[0-24689]|6[2-589]|7[1-37]|9[1347-9])|5(?:33|5[257]))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:562\\d|6(?:[089]\\d{2}|[12][01]\\d|7(?:[1-6]\\d|7[0-4]))|7(?:6[07]|7[457-9]|[89]\\d)\\d)\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"62112345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[056]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"808\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80812345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[08]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"30123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:03|14)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80312345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MD"; + self.countryCode = [NSNumber numberWithInteger:373]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"22|3"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[13-79]|[5-7]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([25-7]\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{8}|[23789]\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:01|1[27]|3\\d|6[02-578]|96)|3(?:7[0135-7]|8[048]|9[0269]))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:51[01]|6(?:0[0-6]|2[016-9]|39))\\d{5}|7(?:[37-9]\\d|42|56)\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"660234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:02[28]|9\\d{2})\\d{2}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8002222"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90(?:02[258]|1(?:23|3[14])|66[136])\\d{2}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9002222"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"870(?:28|87)\\d{2}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8702812"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"697(?:42|56|[7-9]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"697861234"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LI"; + self.countryCode = [NSNumber numberWithInteger:423]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[23789]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6[56]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"697"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(69)(7\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata881 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"612345678"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"612345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"612345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:881]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[67]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"869(?:2(?:29|36)|302|4(?:6[015-9]|70))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8692361234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"869(?:5(?:5[6-8]|6[5-7])|66\\d|76[02-7])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8697652917"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KN"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"869"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataME +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:20[2-8]|3(?:0[2-7]|[12][35-7]|3[4-7])|4(?:0[2367]|1[267])|5(?:0[467]|1[267]|2[367]))\\d{5}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"30234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:00\\d|32\\d|[89]\\d{2}|61\\d|7(?:[0-8]\\d|9(?:[3-9]|[0-2]\\d)))\\d{4}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"67622901"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80080002"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:9(?:4[1568]|5[178]))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"94515151"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"78[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"78108780"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"77\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"77273012"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ME"; + self.countryCode = [NSNumber numberWithInteger:382]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-57-9]|6[036-9]"]; + [numberFormats0_patternArray addObject:@"[2-57-9]|6(?:[03689]|7(?:[0-8]|9[3-9]))"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"679"]; + [numberFormats1_patternArray addObject:@"679[0-2]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(67)(9)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[68]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:1(?:17|2(?:[0189]\\d|[2-6]|7\\d?)|3(?:[01378]|2\\d)|4(?:[024]|10?|3[15]?)|69|7[014])|2(?:17|5(?:[0-36-8]|4\\d?)|69|70)|3(?:17|2(?:[0237]\\d?|[14-689])|34|6[289]|7[01]|81)|4(?:17|2(?:[012]|7?)|4(?:[06]|1\\d?)|5(?:[01357]|[25]\\d?)|69|7[01])|5(?:17|2(?:[0459]|[23678]\\d?)|69|7[01])|6(?:17|2(?:5|6\\d?)|38|42|69|7[01])|7(?:17|2(?:[569]|[234]\\d?)|3(?:0\\d?|[13])|69|7[01]))\\d{4}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"61221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:60|8[125])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"811234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8701\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"870123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:3\\d{2}|86)\\d{5}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"88612345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NA"; + self.countryCode = [NSNumber numberWithInteger:264]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"8[1235]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(6\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"88"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(88)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"870"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(870)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"590(?:[02][79]|13|5[0-268]|[78]7)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"590271234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"690(?:0[0-7]|[1-9]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"690301234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MF"; + self.countryCode = [NSNumber numberWithInteger:590]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[189]1|2[13-7]|3[1-8]|4[157]|5[12457]|6[35-7])[2-57]\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"112345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[0125-8]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"712345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LK"; + self.countryCode = [NSNumber numberWithInteger:94]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-689]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{1})(\\d{6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata882 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]\\d{6,11}" withPossibleNumberPattern:@"\\d{7,12}" withExample:@"3451234567"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"3451234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:2\\d{3}|37\\d{2}|4(?:2|7\\d{3}))\\d{4}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"3451234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:3(?:0[0347]|[13][0139]|2[035]|4[013568]|6[0459]|7[06]|8[15678]|9[0689])\\d{4}|6\\d{5,10})|345\\d{7}" withPossibleNumberPattern:@"\\d{7,12}" withExample:@"3451234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"348[57]\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"3451234567"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:882]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"3[23]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"16|342"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"34[57]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"348"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"16"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"16"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4,5})(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{9}|[28]\\d{7}" withPossibleNumberPattern:@"\\d{6,8}|\\d{10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}|85\\d{6}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"19[123]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1921234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[0-24-9]\\d{2}|3(?:[0-79]\\d|8[02-9]))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"23821234"]; + self.codeID = @"KP"; + self.countryCode = [NSNumber numberWithInteger:850]; + self.internationalPrefix = @"00|99"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20(?:2\\d{2}|4[47]\\d|5[3467]\\d|6[279]\\d|7(?:2[29]|[35]\\d)|8[268]\\d|9[245]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"202123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[2-49]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"321234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"22\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"221234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MG"; + self.countryCode = [NSNumber numberWithInteger:261]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([23]\\d)(\\d{2})(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-57-9]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[03-9]|3[0-5]|4[1-7]|88)\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[0-4]|[79]\\d|8[0-79])\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"751234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"36\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"366711"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NC"; + self.countryCode = [NSNumber numberWithInteger:687]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-46-9]|5[0-4]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1.$2.$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-6]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:247|528|625)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2471234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:235|329|45[56]|545)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2351234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"635\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6351234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MH"; + self.countryCode = [NSNumber numberWithInteger:692]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata883 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"51\\d{7}(?:\\d{3})?" withPossibleNumberPattern:@"\\d{9}(?:\\d{3})?" withExample:@"510012345"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"510012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"510012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"51(?:00\\d{5}(?:\\d{3})?|[13]0\\d{8})" withPossibleNumberPattern:@"\\d{9}(?:\\d{3})?" withExample:@"510012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:883]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"510"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"510"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"51[13]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"007\\d{9,11}|[1-7]\\d{3,9}|8\\d{8}" withPossibleNumberPattern:@"\\d{4,14}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2|3[1-3]|[46][1-4]|5[1-5])(?:1\\d{2,3}|[1-9]\\d{6,7})" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1[0-26-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"1000000000"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:00798\\d{0,2}|80)\\d{7}" withPossibleNumberPattern:@"\\d{9,14}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"602345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"50\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"15\\d{7,8}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"1523456789"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:5(?:44|66|77|88|99)|6(?:00|44|6[16]|70|88)|8(?:00|33|55|77|99))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"15441234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"00798\\d{7,9}" withPossibleNumberPattern:@"\\d{12,14}" withExample:@"007981234567"]; + self.codeID = @"KR"; + self.countryCode = [NSNumber numberWithInteger:82]; + self.internationalPrefix = @"00(?:[124-68]|3\\d{2}|7(?:[0-8]\\d|9[0-79]))"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0(8[1-46-8]|85\\d{2})?"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"00798"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"00798"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:0|1[19]|[69]9|5[458])|[57]0"]; + [numberFormats2_patternArray addObject:@"1(?:0|1[19]|[69]9|5(?:44|59|8))|[57]0"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1(?:[01]|5[1-4]|6[2-8]|[7-9])|[68]0|[3-6][1-9][1-9]"]; + [numberFormats3_patternArray addObject:@"1(?:[01]|5(?:[1-3]|4[56])|6[2-8]|[7-9])|[68]0|[3-6][1-9][1-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"131"]; + [numberFormats4_patternArray addObject:@"1312"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d)(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"131"]; + [numberFormats5_patternArray addObject:@"131[13-9]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"13[2-9]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"30"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"2[1-9]"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3,4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"21[0-46-9]"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3,4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"[3-6][1-9]1"]; + [numberFormats10_patternArray addObject:@"[3-6][1-9]1(?:[0-46-9])"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats10]; + + NSMutableArray *numberFormats11_patternArray = [[NSMutableArray alloc] init]; + [numberFormats11_patternArray addObject:@"1(?:5[46-9]|6[04678]|8[03579])"]; + [numberFormats11_patternArray addObject:@"1(?:5(?:44|66|77|88|99)|6(?:00|44|6[16]|70|88)|8(?:00|33|55|77|99))"]; + NBNumberFormat *numberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats11_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [numberFormats_FormatArray addObject:numberFormats11]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"1(?:0|1[19]|[69]9|5[458])|[57]0"]; + [intlNumberFormats0_patternArray addObject:@"1(?:0|1[19]|[69]9|5(?:44|59|8))|[57]0"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"1(?:[01]|5[1-4]|6[2-8]|[7-9])|[68]0|[3-6][1-9][1-9]"]; + [intlNumberFormats1_patternArray addObject:@"1(?:[01]|5(?:[1-3]|4[56])|6[2-8]|[7-9])|[68]0|[3-6][1-9][1-9]"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"131"]; + [intlNumberFormats2_patternArray addObject:@"1312"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d)(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"131"]; + [intlNumberFormats3_patternArray addObject:@"131[13-9]"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"13[2-9]"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"30"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"2[1-9]"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3,4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + + NSMutableArray *intlNumberFormats7_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats7_patternArray addObject:@"21[0-46-9]"]; + NBNumberFormat *intlNumberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3,4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:intlNumberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats7]; + + NSMutableArray *intlNumberFormats8_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats8_patternArray addObject:@"[3-6][1-9]1"]; + [intlNumberFormats8_patternArray addObject:@"[3-6][1-9]1(?:[0-46-9])"]; + NBNumberFormat *intlNumberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:intlNumberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats8]; + + NSMutableArray *intlNumberFormats9_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats9_patternArray addObject:@"1(?:5[46-9]|6[04678]|8[03579])"]; + [intlNumberFormats9_patternArray addObject:@"1(?:5(?:44|66|77|88|99)|6(?:00|44|6[16]|70|88)|8(?:00|33|55|77|99))"]; + NBNumberFormat *intlNumberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:intlNumberFormats9_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC-$1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats9]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[0289]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:0(?:20|3[1-7]|4[134]|5[14]|6[14578]|7[1-578])|1(?:4[145]|5[14]|6[14-68]|7[169]|88))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:8[089]|9\\d)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"93123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"08\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"08123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"09\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"09123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NE"; + self.countryCode = [NSNumber numberWithInteger:227]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[289]|09"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"08"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(08)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataNF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]\\d{5}" withPossibleNumberPattern:@"\\d{5,6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:06|17|28|39)|3[012]\\d)\\d{3}" withPossibleNumberPattern:@"\\d{5,6}" withExample:@"106609"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[58]\\d{4}" withPossibleNumberPattern:@"\\d{5,6}" withExample:@"381234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NF"; + self.countryCode = [NSNumber numberWithInteger:672]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-578]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[23]\\d|5[124578]|6[01])|3(?:1[3-6]|[23][2-6]|4[2356])|4(?:[23][2-6]|4[3-6]|5[256]|6[25-8]|7[24-6]|8[4-6]))\\d{5}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"22212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[0-25-8]\\d{2}|32\\d|421)\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"72345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[02-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"50012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:0[1-9]|[1-9]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MK"; + self.countryCode = [NSNumber numberWithInteger:389]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[347]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([347]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[58]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([58]\\d{2})(\\d)(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-6]\\d{5,8}|9\\d{5,9}|[78]\\d{5,13}" withPossibleNumberPattern:@"\\d{5,14}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12]\\d{6,7}|9(?:0[3-9]|[1-9]\\d)\\d{5}|(?:3\\d|4[023568]|5[02368]|6[02-469]|7[4-69]|8[2-9])\\d{6}|(?:4[47]|5[14579]|6[1578]|7[0-357])\\d{5,6}|(?:78|41)\\d{5}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:7[34]\\d|8(?:04|[124579]\\d|8[0-3])|95\\d)|287[0-7]|3(?:18[1-8]|88[0-7]|9(?:8[5-9]|6[1-5]))|4(?:28[0-2]|6(?:7[1-9]|8[02-47])|88[0-2])|5(?:2(?:7[7-9]|8\\d)|38[1-79]|48[0-7]|68[4-7])|6(?:2(?:7[7-9]|8\\d)|4(?:3[7-9]|[68][129]|7[04-69]|9[1-8])|58[0-2]|98[7-9])|7(?:38[0-7]|69[1-8]|78[2-4])|8(?:28[3-9]|38[0-2]|4(?:2[12]|3[147-9]|5[346]|7[4-9]|8[014-689]|90)|58[1-8]|78[2-9]|88[5-7])|98[07]\\d)\\d{4}|(?:70[1-689]\\d|8(?:0(?:1[01]|[2-9]\\d)|1(?:[0-8]\\d|9[01]))|90[23589]\\d)\\d{6}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"8021234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7,11}" withPossibleNumberPattern:@"\\d{10,14}" withExample:@"80017591759"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{7,11}" withPossibleNumberPattern:@"\\d{10,14}" withExample:@"7001234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NG"; + self.countryCode = [NSNumber numberWithInteger:234]; + self.internationalPrefix = @"009"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"70|8[01]|90[23589]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[12]|9(?:0[3-9]|[1-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[3-6]|7(?:[1-79]|0[1-9])|8[2-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[78]00"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([78]00)(\\d{4})(\\d{4,5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[78]00"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([78]00)(\\d{5})(\\d{5,6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"78"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(78)(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataML +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[246-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:0(?:2\\d|7[0-8])|1(?:2[5-7]|[3-689]\\d))|44[1239]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:079|17\\d)|[679]\\d{3}|8[239]\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"65012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.codeID = @"ML"; + self.countryCode = [NSNumber numberWithInteger:223]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[246-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"67|74"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[246-9]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[14578]\\d{5,7}|[26]\\d{5,8}|9(?:2\\d{0,2}|[58]|3\\d|4\\d{1,2}|6\\d?|[79]\\d{0,2})\\d{6}" withPossibleNumberPattern:@"\\d{5,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:2\\d{1,2}|[3-5]\\d|6\\d?|[89][0-6]\\d)\\d{4}|2(?:2(?:000\\d{3}|\\d{4})|3\\d{4}|4(?:0\\d{5}|\\d{4})|5(?:1\\d{3,6}|[02-9]\\d{3,5})|[6-9]\\d{4})|4(?:2[245-8]|[346][2-6]|5[3-5])\\d{4}|5(?:2(?:20?|[3-8])|3[2-68]|4(?:21?|[4-8])|5[23]|6[2-4]|7[2-8]|8[24-7]|9[2-7])\\d{4}|6(?:0[23]|1[2356]|[24][2-6]|3[24-6]|5[2-4]|6[2-8]|7(?:[2367]|4\\d|5\\d?|8[145]\\d)|8[245]|9[24])\\d{4}|7(?:[04][24-8]|[15][2-7]|22|3[2-4])\\d{4}|8(?:1(?:2\\d{1,2}|[3-689]\\d)|2(?:2\\d|3(?:\\d|20)|[4-8]\\d)|3[24]\\d|4[24-7]\\d|5[245]\\d|6[23]\\d)\\d{3}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"1234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"17[01]\\d{4}|9(?:2(?:[0-4]|5\\d{2}|6[0-5]\\d)|3[0-36]\\d|4(?:0[0-4]\\d|[1379]\\d|2\\d{2}|4[0-589]\\d|5\\d{2}|88)|5[0-6]|61?\\d|7(?:3\\d|[789]\\d{2})|8\\d|9(?:1\\d|[67]\\d{2}|[089]))\\d{5}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"92123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1333\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"13331234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MM"; + self.countryCode = [NSNumber numberWithInteger:95]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1|2[245]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"251"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"16|2"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"67|81"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[4-8]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"9(?:2[0-4]|[35-9]|4[137-9])"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{4,6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"9(?:3[0-36]|4[0-57-9])"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(9)([34]\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"92[56]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"93"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7,8}|[37-9]\\d{8}|4\\d{6}|5\\d{6,8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:330\\d|4[67]|5\\d|77\\d{2}|88\\d{2}|994\\d)\\d{5}|(?:20\\d{3}|33(?:0\\d{2}|2(?:02|5\\d))|555\\d{2}|77[0567]\\d{2}|88[068]\\d{2}|994\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"770123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[03]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"332(?:0[02]|5\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"332001234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LR"; + self.countryCode = [NSNumber numberWithInteger:231]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2579]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[4-6]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([4-6])(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[38]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12578]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:5[0-7]\\d{5}|[78]\\d{6})|7[5-8]\\d{6}|8\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"18001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NI"; + self.countryCode = [NSNumber numberWithInteger:505]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12569]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:18\\d|2(?:[23]\\d{2}|4(?:[1-35-9]\\d|44)|5(?:0[034]|[2-46]\\d|5[1-3]|7[1-7])))\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"22345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5(?:[05]\\d{2}|1[0-7]\\d|2(?:22|5[25])|66\\d)|6(?:0[034679]\\d|222|5[015-9]\\d|6\\d{2}|7[067]\\d|9[0369]\\d)|9(?:0[09]\\d|22\\d|4[01479]\\d|55\\d|6[0679]\\d|[79]\\d{2}|8[057-9]\\d))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"50012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KW"; + self.countryCode = [NSNumber numberWithInteger:965]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[16]|2(?:[0-35-9]|4[0-35-9])|9[024-9]|52[25]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3,4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"244|5(?:[015]|66)"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12]\\d{7,9}|[57-9]\\d{7}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12](?:1\\d|2(?:[1-3]\\d?|7\\d)|3[2-8]\\d{1,2}|4[2-68]\\d{1,2}|5[1-4689]\\d{1,2})\\d{5}|5[0568]\\d{6}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"50123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:8(?:[05689]\\d|3[01])|9[013-9]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[05-8]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"75123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MN"; + self.countryCode = [NSNumber numberWithInteger:976]; + self.internationalPrefix = @"001"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[12]1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([12]\\d)(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[12]2[1-3]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([12]2\\d)(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[12](?:27|[3-5])"]; + [numberFormats2_patternArray addObject:@"[12](?:27|[3-5]\\d)2"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([12]\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[57-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[12](?:27|[3-5])"]; + [numberFormats4_patternArray addObject:@"[12](?:27|[3-5]\\d)[4-9]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([12]\\d{4})(\\d{4,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2568]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"50123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800[256]\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80021234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LS"; + self.countryCode = [NSNumber numberWithInteger:266]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:0[0-8]|1[49]|2[37]|3[0137]|4[147]|5[05]|6[58]|7[0167]|8[58]|9[139])|2(?:[0235679]\\d|1[0-7]|4[04-9]|8[028])|3(?:[09]\\d|1[014-7]|2[0-3]|3[03]|4[03-57]|55|6[068]|7[06-8]|8[06-9])|4(?:3[013-69]|4\\d|7[0-589])|5(?:[01]\\d|2[0-7]|[56]0|79)|7(?:0[09]|2[0-267]|3[06]|[469]0|5[06-9]|7[0-24-79]|8[7-9])|8(?:09|[34]\\d|5[0134]|8[02])|9(?:0[6-9]|1[016-8]|2[036-8]|3[3679]|40|5[0489]|6[06-9]|7[046-9]|8[36-8]|9[1-9]))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2001234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[16]1|21[89]|8(?:1[01]|7[23]))\\d{4}|6(?:[024-9]\\d|1[0-5]|3[0-24-9])\\d{5}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"60012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[09]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:779|8(?:55|60|7[78])|9(?:00|81))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8601234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PA"; + self.countryCode = [NSNumber numberWithInteger:507]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-57-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[268]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:28[2-57-9]|8[2-57-9]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"28212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:[2356]\\d|8[158])\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"66123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MO"; + self.countryCode = [NSNumber numberWithInteger:853]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([268]\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[1478]|4[124-6]|52)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"31234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"61234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:0[0239]|10)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"808\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80812345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70[67]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70712345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LT"; + self.countryCode = [NSNumber numberWithInteger:370]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"[08]"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"37|4(?:1|5[45]|6[2-4])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([34]\\d)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(8-$1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3[148]|4(?:[24]|6[09])|528|6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3-6]\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(8-$1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[7-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([7-9]\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"52[0-79]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(5)(2\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(8-$1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"345(?:2(?:22|44)|444|6(?:23|38|40)|7(?:4[35-79]|6[6-9]|77)|8(?:00|1[45]|25|[48]8)|9(?:14|4[035-9]))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"3452221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"345(?:32[1-9]|5(?:1[67]|2[5-7]|4[6-8]|76)|9(?:1[67]|2[2-9]|3[689]))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3453231234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}|345976\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"345849\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3458491234"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KY"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"345"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"670(?:2(?:3[3-7]|56|8[5-8])|32[1238]|4(?:33|8[348])|5(?:32|55|88)|6(?:64|70|82)|78[589]|8[3-9]8|989)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6702345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"670(?:2(?:3[3-7]|56|8[5-8])|32[1238]|4(?:33|8[348])|5(?:32|55|88)|6(?:64|70|82)|78[589]|8[3-9]8|989)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6702345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MP"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"670"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[24-9]\\d{3,10}|3(?:[0-46-9]\\d{2,9}|5[013-9]\\d{1,8})" withPossibleNumberPattern:@"\\d{4,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[2-9]\\d{2,9}|(?:[3457]\\d{2}|8(?:0[2-9]|[13-9]\\d)|9(?:0[89]|[2-579]\\d))\\d{1,8})" withPossibleNumberPattern:@"\\d{4,11}" withExample:@"27123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[2679][18]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"628123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[015]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"801\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80112345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20(?:1\\d{5}|[2-689]\\d{1,7})" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"20201234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LU"; + self.countryCode = [NSNumber numberWithInteger:352]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"(15(?:0[06]|1[12]|35|4[04]|55|6[26]|77|88|99)\\d)"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"20"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"2(?:[0367]|4[3-8])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"20"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"2(?:[0367]|4[3-8])"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"2(?:[12589]|4[12])|[3-5]|7[1-9]|8(?:[1-9]|0[2-9])|9(?:[1-9]|0[2-46-9])"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{1,4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"70|80[01]|90[015]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats8]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{4,8}|[2-7]\\d{8}|[89]\\d{6,9}" withPossibleNumberPattern:@"\\d{5,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[0135-8]|2[02-69]|3[0-68]|4[0135-9]|[57]\\d|8[478])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"101234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[1-58]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"612345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4,7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[069]\\d{4,7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"9061234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"85\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"851234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"66\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"662345678"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"140(?:1(?:[035]|[16-8]\\d)|2(?:[0346]|[259]\\d)|3(?:[03568]|[124]\\d)|4(?:[0356]|[17-9]\\d)|5(?:[0358]|[124679]\\d)|7\\d|8[458])" withPossibleNumberPattern:@"\\d{5,6}" withExample:@"14020"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"14\\d{3,4}" withPossibleNumberPattern:@"\\d{5,6}" withExample:nil]; + self.codeID = @"NL"; + self.countryCode = [NSNumber numberWithInteger:31]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1[035]|2[0346]|3[03568]|4[0356]|5[0358]|7|8[4578]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-578]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[16-8]|2[259]|3[124]|4[17-9]|5[124679]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([1-5]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"6[0-57-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(6)(\\d{8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"66"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(66)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"14"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(14)(\\d{3,4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"80|9"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"([89]0\\d)(\\d{4,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataKZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:33\\d|7\\d{2}|80[09])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"33622\\d{5}|7(?:1(?:0(?:[23]\\d|4[023]|59|63)|1(?:[23]\\d|4[0-79]|59)|2(?:[23]\\d|59)|3(?:2\\d|3[1-79]|4[0-35-9]|59)|4(?:2\\d|3[013-79]|4[0-8]|5[1-79])|5(?:2\\d|3[1-8]|4[1-7]|59)|6(?:[234]\\d|5[19]|61)|72\\d|8(?:[27]\\d|3[1-46-9]|4[0-5]))|2(?:1(?:[23]\\d|4[46-9]|5[3469])|2(?:2\\d|3[0679]|46|5[12679])|3(?:[234]\\d|5[139])|4(?:2\\d|3[1235-9]|59)|5(?:[23]\\d|4[01246-8]|59|61)|6(?:2\\d|3[1-9]|4[0-4]|59)|7(?:[237]\\d|40|5[279])|8(?:[23]\\d|4[0-3]|59)|9(?:2\\d|3[124578]|59)))\\d{5}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:0[012578]|47|6[02-4]|7[15-8]|85)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7710009998"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"809\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8091234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"751\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7511234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"751\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7511234567"]; + self.codeID = @"KZ"; + self.countryCode = [NSNumber numberWithInteger:7]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMQ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"596(?:0[2-5]|[12]0|3[05-9]|4[024-8]|[5-7]\\d|89|9[4-8])\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"596301234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"696(?:[0-479]\\d|5[01]|8[0-689])\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"696201234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MQ"; + self.countryCode = [NSNumber numberWithInteger:596]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata888 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{11}" withPossibleNumberPattern:@"\\d{11}" withExample:@"12345678901"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678901"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678901"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{11}" withPossibleNumberPattern:@"\\d{11}" withExample:@"12345678901"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:888]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataLV +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2689]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"63123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"81\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LV"; + self.countryCode = [NSNumber numberWithInteger:371]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2689]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-48]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"25[08]\\d{5}|35\\d{6}|45[1-7]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"35123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[234][0-46-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MR"; + self.countryCode = [NSNumber numberWithInteger:222]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-48]\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[14-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1\\d|4[1-4]|5[1-46]|6[1-7]|7[2-46]|8[2-4])\\d{6}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"11234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"805\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80512345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"801\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80112345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[24]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80212345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PE"; + self.countryCode = [NSNumber numberWithInteger:51]; + self.internationalPrefix = @"19(?:1[124]|77|90)00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" Anexo "; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[4-7]|8[2-4]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([4-8]\\d)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"664491\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6644912345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"66449[2-6]\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6644923456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MS"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"664"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataQA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4[04]\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"44123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3567]\\d{7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"33123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[12]\\d|61)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"QA"; + self.countryCode = [NSNumber numberWithInteger:974]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[28]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([28]\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[3-7]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3-7]\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0\\d{4}|[2-9]\\d{7}" withPossibleNumberPattern:@"\\d{5}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[1-4]|3[1-3578]|5[1-35-7]|6[1-4679]|7[0-8])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4[015-8]|5[89]|87|9\\d)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"40612345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[01]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"82[09]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"82012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"810(?:0[0-6]|[2-8]\\d)\\d{3}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81021234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"880\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"85[0-5]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"85012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0\\d{4}|81(?:0(?:0[7-9]|1\\d)|5\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{5}(?:\\d{3})?" withExample:@"01234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"81[23]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81212345"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NO"; + self.countryCode = [NSNumber numberWithInteger:47]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[489]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([489]\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[235-7]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([235-7]\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataPF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4\\d{5,7}|8\\d{7}" withPossibleNumberPattern:@"\\d{6}(?:\\d{2})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4(?:[09][45689]\\d|4)\\d{4}" withPossibleNumberPattern:@"\\d{6}(?:\\d{2})?" withExample:@"40412345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[79]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"87123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"44\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"441234"]; + self.codeID = @"PF"; + self.countryCode = [NSNumber numberWithInteger:689]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"4[09]|8[79]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"44"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2357-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:0(?:1[0-6]|3[1-4]|[69]\\d)|[1-357]\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21001234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:7(?:210|[79]\\d{2})|9(?:2(?:1[01]|31)|696|8(?:1[1-3]|89|97)|9\\d{2}))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"96961234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800[3467]\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80071234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:0(?:0(?:37|43)|6\\d{2}|70\\d|9[0168])|[12]\\d0[1-5])\\d{3}" withPossibleNumberPattern:@"\\d{8}" withExample:@"50037123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3550\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"35501234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7117\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71171234"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"501\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"50112345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MT"; + self.countryCode = [NSNumber numberWithInteger:356]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataLY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[25679]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[1345]|5[1347]|6[123479]|71)\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[1-6]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"LY"; + self.countryCode = [NSNumber numberWithInteger:218]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([25679]\\d)(\\d{7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-8]\\d{7}|9(?:[1-69]\\d{6,8}|7[2-6]\\d{5,7}|8\\d{8})" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[0-6]\\d|2[13-79][2-6]|3[135-8][2-6]|4[146-9][2-6]|5[135-7][2-6]|6[13-9][2-6]|7[15-9][2-6]|8[1-46-9][2-6]|9[1-79][2-6])\\d{5}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"14567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:6[013]|7[245]|8[0-24-6])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9841234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NP"; + self.countryCode = [NSNumber numberWithInteger:977]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1[2-6]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[01]|[2-8]|9(?:[1-69]|7[15-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9(?:6[013]|7[245]|8)"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d{2})(\\d{7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[0-2]\\d|4[25]\\d|5[34]\\d|64[1-9]|77(?:[0-24]\\d|30)|85[02-46-9]|9[78]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:20150|68\\d{2}|7(?:[0-689]\\d|75)\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"6812345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"180\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"1801234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"275\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2751234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PG"; + self.countryCode = [NSNumber numberWithInteger:675]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[13-689]|27"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"20|7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[03478]\\d|1[0-7]|6[1-69])|4(?:[013568]\\d|2[4-7])|5(?:44\\d|471)|6\\d{2}|8(?:14|3[129]))\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"2012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:2[59]\\d|4(?:2[1-389]|4\\d|7[1-9]|9\\d)|7\\d{2}|8(?:[0-2568]\\d|7[15-8])|9[0-8]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"52512345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[012]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:20|9\\d)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3201234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MU"; + self.countryCode = [NSNumber numberWithInteger:230]; + self.internationalPrefix = @"0(?:0|[2-7]0|33)"; + self.preferredInternationalPrefix = @"020"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-46-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-46-9]\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{5,7}|[3-9]\\d{7,9}|1800\\d{7,9}" withPossibleNumberPattern:@"\\d{5,13}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{5}(?:\\d{2})?|(?:3[2-68]|4[2-9]|5[2-6]|6[2-58]|7[24578]|8[2-8])\\d{7}|88(?:22\\d{6}|42\\d{4})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:81[37]|9(?:0[5-9]|1[024-9]|2[0-35-9]|3[02-9]|4[236-9]|50|7[34-79]|89|9[4-9]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9051234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{7,9}" withPossibleNumberPattern:@"\\d{11,13}" withExample:@"180012345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PH"; + self.countryCode = [NSNumber numberWithInteger:63]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"3(?:23|39|46)|4(?:2[3-6]|[35]9|4[26]|76)|5(?:22|44)|642|8(?:62|8[245])"]; + [numberFormats2_patternArray addObject:@"3(?:230|397|461)|4(?:2(?:35|[46]4|51)|396|4(?:22|63)|59[347]|76[15])|5(?:221|446)|642[23]|8(?:622|8(?:[24]2|5[13]))"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"346|4(?:27|9[35])|883"]; + [numberFormats3_patternArray addObject:@"3469|4(?:279|9(?:30|56))|8834"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[3-8]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([3-8]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"81|9"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(1800)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(1800)(\\d{1,2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMV +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3467]\\d{6}|9(?:00\\d{7}|\\d{6})" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:0[01]|3[0-59])|6(?:[567][02468]|8[024689]|90))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6701234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:46[46]|7[3-9]\\d|9[15-9]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7712345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"781\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7812345"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MV"; + self.countryCode = [NSNumber numberWithInteger:960]; + self.internationalPrefix = @"0(?:0|19)"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[3467]|9(?:[1-9]|0[1-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"900"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataOM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5|[279]\\d)\\d{6}|800\\d{5,6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[2-6]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"23123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[19]\\d{6}|9(?:0[1-9]|[1-9]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"92123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8007\\d{4,5}|500\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"80071234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"OM"; + self.countryCode = [NSNumber numberWithInteger:968]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[79]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([79]\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[58]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([58]00)(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[458]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:444|888)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4441234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"55[5-9]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5551234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NR"; + self.countryCode = [NSNumber numberWithInteger:674]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:\\d{2})?|[2789]\\d{2})\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[2-9]|21\\d{2})\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"1234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:111|77\\d|88\\d|99\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"991234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MW"; + self.countryCode = [NSNumber numberWithInteger:265]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[1789]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{9,10}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:33|55|81)\\d{8}|(?:2(?:0[01]|2[2-9]|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|7[1-8]|9[1-5])|4(?:1[1-57-9]|[24-6][1-9]|[37][1-8]|8[1-35-9]|9[2-689])|5(?:88|9[1-79])|6(?:1[2-68]|[234][1-9]|5[1-3689]|6[12457-9]|7[1-7]|8[67]|9[4-8])|7(?:[13467][1-9]|2[1-8]|5[13-9]|8[1-69]|9[17])|8(?:2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[1-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69][1-9]|7[12]|8[1-8]))\\d{7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"2221234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:(?:33|55|81)\\d{8}|(?:2(?:2[2-9]|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|7[1-8]|9[1-5])|4(?:1[1-57-9]|[24-6][1-9]|[37][1-8]|8[1-35-9]|9[2-689])|5(?:88|9[1-79])|6(?:1[2-68]|[2-4][1-9]|5[1-3689]|6[12457-9]|7[1-7]|8[67]|9[4-8])|7(?:[13467][1-9]|2[1-8]|5[13-9]|8[1-69]|9[17])|8(?:2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[1-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69][1-9]|7[12]|8[1-8]))\\d{7})" withPossibleNumberPattern:@"\\d{11}" withExample:@"12221234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|88)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"300\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3001234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"500\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5001234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MX"; + self.countryCode = [NSNumber numberWithInteger:52]; + self.internationalPrefix = @"0[09]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"01"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0[12]|04[45](\\d{10})"; + self.nationalPrefixTransformRule = @"1$1"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"33|55|81"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([358]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2467]|3[0-2457-9]|5[089]|8[02-9]|9[0-35-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:33|55|81)"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1)([358]\\d)(\\d{4})(\\d{4})" withFormat:@"044 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1(?:[2467]|3[0-2457-9]|5[089]|8[2-9]|9[1-35-9])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"044 $2 $3 $4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"33|55|81"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([358]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"[2467]|3[0-2457-9]|5[089]|8[02-9]|9[0-35-9]"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"1(?:33|55|81)"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1)([358]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"1(?:[2467]|3[0-2457-9]|5[089]|8[2-9]|9[1-35-9])"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataPK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{8}|[2-8]\\d{5,11}|9(?:[013-9]\\d{4,9}|2\\d(?:111\\d{6}|\\d{3,7}))" withPossibleNumberPattern:@"\\d{6,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:21|42)[2-9]\\d{7}|(?:2[25]|4[0146-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]\\d{6}|(?:2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:1|2[2-8]|3[27-9]|4[2-6]|6[3569]|9[25-8]))[2-9]\\d{5,6}|58[126]\\d{7}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"2123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:0\\d|1[0-6]|2[0-5]|3[0-7]|4[0-8]|55|64)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3012345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"122\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"122044444"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[125]|3[2358]|4[2-4]|9[2-8])|4(?:[0-246-9]|5[3479])|5(?:[1-35-7]|4[2-467])|6(?:[1-8]|0[468])|7(?:[14]|2[236])|8(?:[16]|2[2-689]|3[23578]|4[3478]|5[2356])|9(?:1|22|3[27-9]|4[2-6]|6[3569]|9[2-7]))111\\d{6}" withPossibleNumberPattern:@"\\d{11,12}" withExample:@"21111825888"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PK"; + self.countryCode = [NSNumber numberWithInteger:92]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)1"]; + [numberFormats0_patternArray addObject:@"(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)11"]; + [numberFormats0_patternArray addObject:@"(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)111"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(111)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[349]|45|54|60|72|8[2-5]|9[2-9]"]; + [numberFormats1_patternArray addObject:@"(?:2[349]|45|54|60|72|8[2-5]|9[2-9])\\d1"]; + [numberFormats1_patternArray addObject:@"(?:2[349]|45|54|60|72|8[2-5]|9[2-9])\\d11"]; + [numberFormats1_patternArray addObject:@"(?:2[349]|45|54|60|72|8[2-5]|9[2-9])\\d111"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(111)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{7,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"2[349]|45|54|60|72|8[2-5]|9[2-9]"]; + [numberFormats3_patternArray addObject:@"(?:2[349]|45|54|60|72|8[2-5]|9[2-9])\\d[2-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{6,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(3\\d{2})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"58[12]|1"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"([15]\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"586"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(586\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"[89]00"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"([89]00)(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13-9]\\d{7,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[2-9]\\d|[4-9][2-9])\\d{6}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"323456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:1[1-5]\\d{2}|[02-4679][2-9]\\d|59\\d{2}|8(?:1[23]|[2-9]\\d))\\d{5}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1[378]00\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1300123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1600\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1600123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"154\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1541234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MY"; + self.countryCode = [NSNumber numberWithInteger:60]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[4-79]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([4-79])(\\d{3})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(3)(\\d{4})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[02-46-9][1-9]|8"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([18]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1[36-8]0"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)([36-8]00)(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"11"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(11)(\\d{4})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"15"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(15[49])(\\d{3})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-5]\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[34]\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:@"4002"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[125]\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:@"1234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NU"; + self.countryCode = [NSNumber numberWithInteger:683]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[12]\\d{6,8}|[3-57-9]\\d{8}|6\\d{5,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])\\d{7}|[12]2\\d{5}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[0137]|6[069]|7[2389]|88)\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"512345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"801\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"39\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"391234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"64\\d{4,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"641234567"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PL"; + self.countryCode = [NSNumber numberWithInteger:48]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[14]|2[0-57-9]|3[2-4]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[12]2"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{1})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"26|39|5[0137]|6[0469]|7[02389]|8[08]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"64"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"64"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataMZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[28]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[1346]\\d|5[0-2]|[78][12]|93)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[23467]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"821234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MZ"; + self.countryCode = [NSNumber numberWithInteger:258]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2|8[2-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([28]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[45]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"41\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"411234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"55\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"551234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PM"; + self.countryCode = [NSNumber numberWithInteger:508]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([45]\\d)(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataRE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[268]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"262\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"262161234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:9[23]|47)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"692123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89[1-37-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"891123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:1[019]|2[0156]|84|90)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"810123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RE"; + self.countryCode = [NSNumber numberWithInteger:262]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([268]\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = @"262|6[49]|8"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{7,8}|(?:[2-467]|92)\\d{7}|5\\d{8}|8\\d{9}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"11\\d{7}|1?(?:2[24-8]|3[35-8]|4[3-68]|6[2-5]|7[235-7])\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"112345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5(?:[013-689]\\d|7[0-26-8])|811\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"512345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"92[05]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"920012345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SA"; + self.countryCode = [NSNumber numberWithInteger:966]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-467]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-467])(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[1-467]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"92"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(92\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"81"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(811)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{4,6}" withPossibleNumberPattern:@"\\d{5,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[4-79]|[23]\\d|4[0-2]|5[03]|6[0-37])\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"40123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"48\\d{3}|7(?:30|[46-8]\\d|5[025-9]|9[0-5])\\d{4}|8[4-9]\\d{5}|9(?:1[2-9]|2[013-9]|3[0-2]|[46]\\d|5[0-46-9]|7[0-689]|8[0-79]|9[0-8])\\d{4}" withPossibleNumberPattern:@"\\d{5,7}" withExample:@"7421234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1[38]\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"18123"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[12]\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"51123"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SB"; + self.countryCode = [NSNumber numberWithInteger:677]; + self.internationalPrefix = @"0[01]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[7-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataNZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[235-9]\\d{6}|[2-57-9]\\d{7,10}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[2-79]|[49][2-9]|6[235-9]|7[2-57-9])\\d{6}|24099\\d{3}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"32345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[028]\\d{7,8}|1(?:[03]\\d{5,7}|[12457]\\d{5,6}|[689]\\d{5})|[79]\\d{7})" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"211234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"508\\d{6,7}|80\\d{6,8}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{7,9}" withPossibleNumberPattern:@"\\d{9,11}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[28]6\\d{6,7}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"26123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NZ"; + self.countryCode = [NSNumber numberWithInteger:64]; + self.internationalPrefix = @"0(?:0|161)"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[346]|7[2-57-9]|9[1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([34679])(\\d{3})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"240"]; + [numberFormats1_patternArray addObject:@"2409"]; + [numberFormats1_patternArray addObject:@"24099"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(24099)(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"21"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"2(?:1[1-9]|[69]|7[0-35-9])|70|86"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"2[028]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d)(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"2(?:10|74)|5|[89]0"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2468]\\d{5,6}" withPossibleNumberPattern:@"\\d{6,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4[2-46]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4217123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[5-8]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2510123"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8000\\d{2}" withPossibleNumberPattern:@"\\d{6}" withExample:@"800000"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"64\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6412345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SC"; + self.countryCode = [NSNumber numberWithInteger:248]; + self.internationalPrefix = @"0[0-2]"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[246]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[19]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:[125]\\d|8[3567])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"121231234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[0-3569]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"911231234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SD"; + self.countryCode = [NSNumber numberWithInteger:249]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5789]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:787|939)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7872345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:787|939)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7872345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PR"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"787|939"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-35-9]\\d{5,11}|4\\d{6,8}" withPossibleNumberPattern:@"\\d{6,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:0[1-8]\\d{6}|[136]\\d{5,7}|(?:2[0-35]|4[0-4]|5[0-25-9]|7[13-6]|[89]\\d)\\d{5,6})|2(?:[136]\\d{5,7}|(?:2[0-7]|4[0136-8]|5[0138]|7[018]|8[01]|9[0-57])\\d{5,6})|3(?:[356]\\d{5,7}|(?:0[0-4]|1\\d|2[0-25]|4[056]|7[0-2]|8[0-3]|9[023])\\d{5,6})|4(?:[0246]\\d{5,7}|(?:1[013-8]|3[0135]|5[14-79]|7[0-246-9]|8[0156]|9[0-689])\\d{5,6})|5(?:0[0-6]|[15][0-5]|2[0-68]|3[0-4]|4\\d|6[03-5]|7[013]|8[0-79]|9[01])\\d{5,6}|6(?:[03]\\d{5,7}|(?:1[1-3]|2[0-4]|4[02-57]|5[0-37]|6[0-3]|7[0-2]|8[0247]|9[0-356])\\d{5,6})|8\\d{6,8}|9(?:0[1-9]\\d{4,6}|(?:1[0-68]|2\\d|3[02-5]|4[0-3]|5[0-4]|[68][01]|7[0135-8])\\d{5,6})" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"8123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[02369]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20\\d{4,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"20123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"649\\d{6}|9(?:00|39|44)[1-8]\\d{3,6}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"77(?:0\\d{3}(?:\\d{3})?|[1-7]\\d{6})" withPossibleNumberPattern:@"\\d{6}(?:\\d{3})?" withExample:@"771234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"75[1-8]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"751234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"74[02-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"740123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:25[245]|67[3-6])\\d{9}" withPossibleNumberPattern:@"\\d{12}" withExample:@"254123456789"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SE"; + self.countryCode = [NSNumber numberWithInteger:46]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(8)(\\d{2,3})(\\d{2,3})(\\d{2})" withFormat:@"$1-$2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|90"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([1-69]\\d)(\\d{2,3})(\\d{2})(\\d{2})" withFormat:@"$1-$2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[136]|2[136]|3[356]|4[0246]|6[03]|90"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([1-469]\\d)(\\d{3})(\\d{2})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1-$2 $3 $4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2,3})(\\d{2})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1-$2 $3 $4" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(77)(\\d{2})(\\d{2})" withFormat:@"$1-$2$3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"20"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(20)(\\d{2,3})(\\d{2})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"9[034]"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(9[034]\\d)(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1-$2 $3 $4" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"9[034]"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(9[034]\\d)(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"25[245]|67[3-6]"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1-$2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"8"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(8)(\\d{2,3})(\\d{2,3})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|90"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([1-69]\\d)(\\d{2,3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"1[136]|2[136]|3[356]|4[0246]|6[03]|90"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([1-469]\\d)(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2,3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"7"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"7"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(77)(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + + NSMutableArray *intlNumberFormats7_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats7_patternArray addObject:@"20"]; + NBNumberFormat *intlNumberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(20)(\\d{2,3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats7_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats7]; + + NSMutableArray *intlNumberFormats8_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats8_patternArray addObject:@"9[034]"]; + NBNumberFormat *intlNumberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(9[034]\\d)(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats8_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats8]; + + NSMutableArray *intlNumberFormats9_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats9_patternArray addObject:@"9[034]"]; + NBNumberFormat *intlNumberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(9[034]\\d)(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats9_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats9]; + + NSMutableArray *intlNumberFormats10_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats10_patternArray addObject:@"25[245]|67[3-6]"]; + NBNumberFormat *intlNumberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:intlNumberFormats10_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats10]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[24589]\\d{7,8}|1(?:[78]\\d{8}|[49]\\d{2,3})" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:22[234789]|42[45]|82[01458]|92[369])\\d{5}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"22234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[69]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"599123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:4|9\\d)\\d{2}" withPossibleNumberPattern:@"\\d{4,5}" withExample:@"19123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1700\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1700123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PS"; + self.countryCode = [NSNumber numberWithInteger:970]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2489]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2489])(2\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(5[69]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[78]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1[78]00)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:@"8999"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TA"; + self.countryCode = [NSNumber numberWithInteger:290]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-46-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[12]\\d|[35][1-689]|4[1-59]|6[1-35689]|7[1-9]|8[1-69]|9[1256])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:[1236]\\d{2}|480)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[02]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:0[178]|4[68])\\d{6}|76(?:0[1-57]|1[2-47]|2[237])\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"760123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:8\\d|9[1579])\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"808123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"884[0-4689]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"884123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"301234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:0(?:7\\d|8[17]))\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"707123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"600\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"600110000"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PT"; + self.countryCode = [NSNumber numberWithInteger:351]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2[12]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[3-9]|[346-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([2-46-9]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[36]\\d{7}|[17-9]\\d{7,10}" withPossibleNumberPattern:@"\\d{8,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[1-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"61234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:8[1-8]|9[0-8])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1?800\\d{7}" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"18001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1900\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"19001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[12]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"31234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7000\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"70001234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SG"; + self.countryCode = [NSNumber numberWithInteger:65]; + self.internationalPrefix = @"0[0-3]\\d"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[369]|8[1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([3689]\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[89]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(1[89]00)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"70"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(7000)(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"649(?:712|9(?:4\\d|50))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6497121234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"649(?:2(?:3[129]|4[1-7])|3(?:3[1-389]|4[1-8])|4[34][1-3])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6492311234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"64971[01]\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6497101234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TC"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"649"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[256]\\d{4}" withPossibleNumberPattern:@"\\d{4,5}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[0-57-9]\\d|6[4-9])\\d{2}" withPossibleNumberPattern:@"\\d{5}" withExample:@"22158"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"262\\d{2}" withPossibleNumberPattern:@"\\d{5}" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SH"; + self.countryCode = [NSNumber numberWithInteger:290]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2679]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"22(?:[3789]0|5[0-5]|6[89])\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22501234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[023568]\\d|77\\d|9\\d{2})\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"63012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TD"; + self.countryCode = [NSNumber numberWithInteger:235]; + self.internationalPrefix = @"00|16"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{6,7}|[89]\\d{4,7}" withPossibleNumberPattern:@"\\d{5,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1\\d|[25][2-8]|3[24-8]|4[24-8]|7[3-8])\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"11234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[37][01]|4[0139]|51|6[48])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"31234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{4,6}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{4,6}|89[1-3]\\d{2,5}" withPossibleNumberPattern:@"\\d{5,8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:59|8[1-3])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"59012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SI"; + self.countryCode = [NSNumber numberWithInteger:386]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[12]|3[24-8]|4[24-8]|5[2-8]|7[3-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[37][01]|4[0139]|51|6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3-7]\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89][09]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([89][09])(\\d{3,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"59|8[1-3]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([58]\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2552255|(?:277|345|488|5(?:35|44|87)|6(?:22|54|79)|7(?:33|47)|8(?:24|55|76))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2771234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[234689]0|77[45789])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6201234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PW"; + self.countryCode = [NSNumber numberWithInteger:680]; + self.internationalPrefix = @"01[12]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSJ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0\\d{4}|[4789]\\d{7}" withPossibleNumberPattern:@"\\d{5}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"79\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"79123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4[015-8]|5[89]|9\\d)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"41234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[01]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"82[09]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"82012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"810(?:0[0-6]|[2-8]\\d)\\d{3}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81021234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"880\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"85[0-5]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"85012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0\\d{4}|81(?:0(?:0[7-9]|1\\d)|5\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{5}(?:\\d{3})?" withExample:@"01234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"81[23]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81212345"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SJ"; + self.countryCode = [NSNumber numberWithInteger:47]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataUA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3-9]\\d{8}" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[1-8]|4[13-8]|5[1-7]|6[12459])\\d{7}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"311234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:39|50|6[36-8]|73|9[1-9])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"391234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"891234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"UA"; + self.countryCode = [NSNumber numberWithInteger:380]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = @"0~0"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[38]9|4(?:[45][0-5]|87)|5(?:0|6[37]|7[37])|6[36-8]|73|9[1-9]"]; + [numberFormats0_patternArray addObject:@"[38]9|4(?:[45][0-5]|87)|5(?:0|6(?:3[14-7]|7)|7[37])|6[36-8]|73|9[1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([3-9]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3[1-8]2|4[13678]2|5(?:[12457]2|6[24])|6(?:[49]2|[12][29]|5[24])|8[0-8]|90"]; + [numberFormats1_patternArray addObject:@"3(?:[1-46-8]2[013-9]|52)|4(?:[1378]2|62[013-9])|5(?:[12457]2|6[24])|6(?:[49]2|[12][29]|5[24])|8[0-8]|90"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3-689]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"3(?:5[013-9]|[1-46-8])|4(?:[137][013-9]|6|[45][6-9]|8[4-6])|5(?:[1245][013-9]|6[0135-9]|3|7[4-6])|6(?:[49][013-9]|5[0135-9]|[12][13-8])"]; + [numberFormats2_patternArray addObject:@"3(?:5[013-9]|[1-46-8](?:22|[013-9]))|4(?:[137][013-9]|6(?:[013-9]|22)|[45][6-9]|8[4-6])|5(?:[1245][013-9]|6(?:3[02389]|[015689])|3|7[4-6])|6(?:[49][013-9]|5[0135-9]|[12][13-8])"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([3-6]\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataRO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{5,8}|[37-9]\\d{8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:1(?:\\d{7}|9\\d{3})|[3-6](?:\\d{7}|\\d9\\d{2}))|3[13-6]\\d{7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"211234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[0-8]\\d{2}|99\\d)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"712345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[036]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"801\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"802\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"802123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"37\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"372123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RO"; + self.countryCode = [NSNumber numberWithInteger:40]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" int "; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[23]1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"21"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(21)(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[23][3-7]|[7-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"2[3-6]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d{2})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-68]\\d{5,8}|9\\d{6,8})" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:16\\d{3,4}|\\d{8})|[3-5](?:[1-8]16\\d{2,3}|\\d{8})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:0(?:[1-8]\\d|9[1-9])|(?:1[0-24-9]|4[0489]|50)\\d)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:[78]\\d{7}|00\\d{6})" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[5-9]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"850123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:02|5[0-4]|9[0-6])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"690123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9090\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9090123"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"96\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"961234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:602|8(?:00|[5-9]\\d)|9(?:00|[78]\\d))\\d{6}|9090\\d{3}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"800123456"]; + self.codeID = @"SK"; + self.countryCode = [NSNumber numberWithInteger:421]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"216"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(16)(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[3-5]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3-5]\\d)(16)(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{3})(\\d{3})(\\d{2})" withFormat:@"$1/$2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[3-5]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([3-5]\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1/$2 $3 $4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[689]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([689]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"9090"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(9090)(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataPY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[0-5]\\d{4,7}|[2-46-9]\\d{5,8}" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[26]1|3[289]|4[124678]|7[123]|8[1236])\\d{5,7}|(?:2(?:2[4568]|7[15]|9[1-5])|3(?:18|3[167]|4[2357]|51)|4(?:18|2[45]|3[12]|5[13]|64|71|9[1-47])|5(?:[1-4]\\d|5[0234])|6(?:3[1-3]|44|7[1-4678])|7(?:17|4[0-4]|6[1-578]|75|8[0-8])|858)\\d{5,6}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:6[12]|[78][1-6]|9[1-5])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"961456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8700[0-4]\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"870012345"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]0\\d{4,7}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"201234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PY"; + self.countryCode = [NSNumber numberWithInteger:595]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:[26]1|3[289]|4[124678]|7[123]|8[1236])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-9]0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9[1-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8700"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[2-8][1-9]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[29]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:2[2-7]|3[23]|44|55|66|77)\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[0-389]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90112345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TG"; + self.countryCode = [NSNumber numberWithInteger:228]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{7}" withPossibleNumberPattern:@"\\d{6,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235]2[2-4][2-9]\\d{4}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"22221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[15]|3[03-5]|4[04]|5[05]|66|7[6-9]|88|99)\\d{6}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"25123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SL"; + self.countryCode = [NSNumber numberWithInteger:232]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{7,8}|1\\d{3}(?:\\d{5,6})?" withPossibleNumberPattern:@"\\d{4}|\\d{8,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2\\d|3[2-9]|4[2-5]|5[2-6]|7[3-7])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:14|6[1-4]|[89]\\d)\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"812345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1900\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[08]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"601234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:@"1100"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:@"1100"]; + self.codeID = @"TH"; + self.countryCode = [NSNumber numberWithInteger:66]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"14|[3-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([13-9]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1[89]00)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[05-7]\\d{7,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0549(?:8[0157-9]|9\\d)\\d{4}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"0549886377"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[16]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"66661212"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[178]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[158]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"58001110"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SM"; + self.countryCode = [NSNumber numberWithInteger:378]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"(?:0549)?([89]\\d{5})"; + self.nationalPrefixTransformRule = @"0549$1"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[5-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(0549)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{6})" withFormat:@"0549 $1" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[5-7]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"0"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(0549)(\\d{6})" withFormat:@"($1) $2" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{6})" withFormat:@"(0549) $1" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataSN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3789]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:0(?:1[0-2]|80)|282|3(?:8[1-9]|9[3-9])|611|90[1-5])\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"301012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[067]\\d|21|8[0-46]|90)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"88[4689]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"884123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"81[02468]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"810123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3392\\d{5}|93330\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"933301234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SN"; + self.countryCode = [NSNumber numberWithInteger:221]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[379]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataRS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[126-9]\\d{4,11}|3(?:[0-79]\\d{3,10}|8[2-9]\\d{2,9})" withPossibleNumberPattern:@"\\d{5,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:[02-9][2-9]|1[1-9])\\d|2(?:[0-24-7][2-9]\\d|[389](?:0[2-9]|[2-9]\\d))|3(?:[0-8][2-9]\\d|9(?:[2-9]\\d|0[2-9])))\\d{3,8}" withPossibleNumberPattern:@"\\d{5,12}" withExample:@"10234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:[0-689]|7\\d)\\d{6,7}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"601234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{3,9}" withPossibleNumberPattern:@"\\d{6,12}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:90[0169]|78\\d)\\d{3,7}" withPossibleNumberPattern:@"\\d{6,12}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[06]\\d{4,10}" withPossibleNumberPattern:@"\\d{6,12}" withExample:@"700123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RS"; + self.countryCode = [NSNumber numberWithInteger:381]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:2[389]|39)0"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([23]\\d{2})(\\d{4,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1|2(?:[0-24-7]|[389][1-9])|3(?:[0-8]|9[1-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([1-3]\\d)(\\d{5,10})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(6\\d)(\\d{6,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{3,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"7[26]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(7[26])(\\d{4,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"7[08]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(7[08]\\d)(\\d{4,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTJ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3-589]\\d{8}" withPossibleNumberPattern:@"\\d{3,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:1[3-5]|2[245]|3[12]|4[24-7]|5[25]|72)|4(?:46|74|87))\\d{6}" withPossibleNumberPattern:@"\\d{3,9}" withExample:@"372123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:41[18]|50[125]|88\\d|9[0-35-9]\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"917123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TJ"; + self.countryCode = [NSNumber numberWithInteger:992]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[34]7|91[78]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([349]\\d{2})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(8) $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"4[148]|[58]|9(?:1[59]|[0235-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([4589]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(8) $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"331"]; + [numberFormats2_patternArray addObject:@"3317"]; + [numberFormats2_patternArray addObject:@"33170"]; + [numberFormats2_patternArray addObject:@"331700"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(331700)(\\d)(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(8) $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"3[1-5]"]; + [numberFormats3_patternArray addObject:@"3(?:[1245]|3(?:[02-9]|1[0-589]))"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d)(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(8) $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:0(?:878\\d{5}|6698\\d{5})|[1589]\\d{5,10}|3(?:[12457-9]\\d{8}|[36]\\d{7,9}))" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"06698\\d{5}" withPossibleNumberPattern:@"\\d{10}" withExample:@"0669812345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:[12457-9]\\d{8}|6\\d{7,8}|3\\d{7,9})" withPossibleNumberPattern:@"\\d{9,11}" withExample:@"3123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:0\\d{6}|3\\d{3})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0878\\d{5}|1(?:44|6[346])\\d{6}|89(?:2\\d{3}|4(?:[0-4]\\d{2}|[5-9]\\d{4})|5(?:[0-4]\\d{2}|[5-9]\\d{6})|9\\d{6})" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"899123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"84(?:[08]\\d{6}|[17]\\d{3})" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"848123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:78\\d|99)\\d{6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"1781234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"55\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"848\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"848123456"]; + self.codeID = @"VA"; + self.countryCode = [NSNumber numberWithInteger:39]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataSO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-79]\\d{6,8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1\\d|2[0-79]|3[0-46-8]|4[0-7]|59)\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:15\\d|2(?:4\\d|8)|6[1-35-9]?\\d{2}|7(?:[1-8]\\d|99?\\d)|9(?:0[67]|[2-9])\\d)\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"71123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SO"; + self.countryCode = [NSNumber numberWithInteger:252]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2[0-79]|[13-5]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"24|[67]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"15|28|6[1-35-9]|799|9[2-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"90"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(90\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-47]\\d{3,6}" withPossibleNumberPattern:@"\\d{4,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[2-4]|[34]\\d)\\d{2,5}" withPossibleNumberPattern:@"\\d{4,7}" withExample:@"3101"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[2-4]\\d{2,5}" withPossibleNumberPattern:@"\\d{4,7}" withExample:@"7290"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TK"; + self.countryCode = [NSNumber numberWithInteger:690]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataUG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"20(?:[0147]\\d{2}|2(?:40|[5-9]\\d)|3[23]\\d|5[0-4]\\d|6[03]\\d|8[0-2]\\d)\\d{4}|[34]\\d{8}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"312345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2030\\d{5}|7(?:0[0-7]|[15789]\\d|2[03]|30|[46][0-4])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"712345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800[123]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[123]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"901123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"UG"; + self.countryCode = [NSNumber numberWithInteger:256]; + self.internationalPrefix = @"00[057]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[7-9]|20(?:[013-8]|2[5-9])|4(?:6[45]|[7-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3|4(?:[1-5]|6[0-36-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"2024"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(2024)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataRU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3489]\\d{9}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:0[12]|4[1-35-79]|5[1-3]|65|8[1-58]|9[0145])|4(?:01|1[1356]|2[13467]|7[1-5]|8[1-7]|9[1-689])|8(?:1[1-8]|2[01]|3[13-6]|4[0-8]|5[15]|6[1-35-79]|7[1-37-9]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3011234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{9}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[04]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[39]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8091234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RU"; + self.countryCode = [NSNumber numberWithInteger:7]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-79]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[34689]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([3489]\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"8 ($1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"8 ($1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[34689]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([3489]\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"8 ($1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"8 ($1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-489]\\d{6}|7\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[1-5]|3[1-9]|4[1-4])\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2112345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[3-8]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"77212345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TL"; + self.countryCode = [NSNumber numberWithInteger:670]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-489]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5789]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"784(?:266|3(?:6[6-9]|7\\d|8[0-24-6])|4(?:38|5[0-36-8]|8[0-8])|5(?:55|7[0-2]|93)|638|784)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7842661234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"784(?:4(?:3[0-4]|5[45]|89|9[0-58])|5(?:2[6-9]|3[0-4]))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7844301234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"VC"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"784"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata870 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[35-7]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"301234567"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"301234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[356]\\d|7[6-8])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"301234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:870]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-6]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:2\\d|3[1-9])|2(?:22|4[0-35-8])|3(?:22|4[03-9])|4(?:22|3[128]|4\\d|6[15])|5(?:22|5[7-9]|6[014-689]))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[1-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"66123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TM"; + self.countryCode = [NSNumber numberWithInteger:993]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"12"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(8 $1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"13|[2-5]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d)(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(8 $1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{5,6}" withPossibleNumberPattern:@"\\d{6,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[1-3]|3[0-7]|4\\d|5[2-58]|68\\d)\\d{4}" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"211234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:7[124-7]|8[1-9])\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7412345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:6\\d{4}|90[0-4]\\d{3})" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"561234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SR"; + self.countryCode = [NSNumber numberWithInteger:597]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-4]|5[2-58]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"56"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"59|[6-8]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataRW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[027-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[258]\\d{7}|06\\d{6}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"250123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[238]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"720123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RW"; + self.countryCode = [NSNumber numberWithInteger:250]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[7-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([7-9]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(0\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataTN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-57-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:[012]\\d|6[0-4]|91)\\d{5}|7\\d{7}|81200\\d{3}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[259]\\d|4[0-6])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8010\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80101234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"88\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[12]10\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81101234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TN"; + self.countryCode = [NSNumber numberWithInteger:216]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[24589]\\d{9}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:12|3[457-9]|[58][1-9]|[467]\\d|9[1-6])|50[01])\\d{7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"2121234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4(?:1[24-8]|2[46])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"4121234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"VE"; + self.countryCode = [NSNumber numberWithInteger:58]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[19]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"181234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:12|9[1257])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"977123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SS"; + self.countryCode = [NSNumber numberWithInteger:211]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[02-8]\\d{4,6}" withPossibleNumberPattern:@"\\d{5,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2\\d|3[1-8]|4[1-4]|[56]0|7[0149]|8[05])\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"20123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:7[578]|8[47-9])\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7715123"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0800\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"0800222"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TO"; + self.countryCode = [NSNumber numberWithInteger:676]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-6]|7[0-4]|8[05]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7[5-9]|8[47-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataST +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[29]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"22\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:0(?:0[5-9]|[1-9]\\d)|[89]\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9812345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ST"; + self.countryCode = [NSNumber numberWithInteger:239]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"284(?:(?:229|4(?:22|9[45])|774|8(?:52|6[459]))\\d{4}|496[0-5]\\d{3})" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2842291234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"284(?:(?:3(?:0[0-3]|4[0-367]|94)|4(?:4[0-6]|68|99)|54[0-57])\\d{4}|496[6-9]\\d{3})" withPossibleNumberPattern:@"\\d{10}" withExample:@"2843001234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"VG"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"284"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSV +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[267]\\d{7}|[89]\\d{6}(?:\\d{4})?" withPossibleNumberPattern:@"\\d{7,8}|\\d{11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[1-6]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4}(?:\\d{4})?" withPossibleNumberPattern:@"\\d{7}(?:\\d{4})?" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{4}(?:\\d{4})?" withPossibleNumberPattern:@"\\d{7}(?:\\d{4})?" withExample:@"9001234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SV"; + self.countryCode = [NSNumber numberWithInteger:503]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[267]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-589]\\d{9}|444\\d{4}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[13][26]|[28][2468]|[45][268]|[67][246])|3(?:[13][28]|[24-6][2468]|[78][02468]|92)|4(?:[16][246]|[23578][2468]|4[26]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:0[1-7]|22|[34]\\d|5[1-59]|9[246])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5012345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"512\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5123456789"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"444\\d{4}|850\\d{7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"4441444"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"444\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"4441444"]; + self.codeID = @"TR"; + self.countryCode = [NSNumber numberWithInteger:90]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[23]|4(?:[0-35-9]|4[0-35-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[589]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"444"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(444)(\\d{1})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"340(?:2(?:01|2[0678]|44|77)|3(?:32|44)|4(?:22|7[34])|5(?:1[34]|55)|6(?:26|4[23]|77|9[023])|7(?:1[2-589]|27|7\\d)|884|998)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"3406421234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"340(?:2(?:01|2[0678]|44|77)|3(?:32|44)|4(?:22|7[34])|5(?:1[34]|55)|6(?:26|4[23]|77|9[023])|7(?:1[2-589]|27|7\\d)|884|998)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"3406421234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"VI"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"340"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5789]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7215(?:4[2-8]|8[239]|9[056])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7215425678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7215(?:1[02]|2\\d|5[034679]|8[014-8])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7215205678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SX"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"721"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataWF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[4-8]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:50|68|72)\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"501234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:50|68|72|8[23])\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"501234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[48]0\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"401234"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"WF"; + self.countryCode = [NSNumber numberWithInteger:681]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"868(?:2(?:01|2[1-6]|3[1-5])|6(?:0[79]|1[02-8]|2[1-9]|[3-69]\\d|7[0-79])|82[124])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8682211234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"868(?:2(?:[789]\\d)|3(?:0[1-9]|1[02-9]|[2-9]\\d)|4[6-9]\\d|6(?:20|78|8\\d)|7(?:0[1-9]|1[02-9]|[2-9]\\d))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8682911234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"868619\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TT"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"868"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-59]\\d{7,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:1\\d?|4\\d|[2356])|2(?:1\\d?|[235])|3(?:[13]\\d|4)|4[13]|5[1-3])\\d{6}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"112345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:22|[35][0-8]|4\\d|6[024-9]|88|9[0-489])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"944567890"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SY"; + self.countryCode = [NSNumber numberWithInteger:963]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-5]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataSZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[027]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[2-5]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22171234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[6-8]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"76123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0800\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"08001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0800\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"08001234"]; + self.codeID = @"SZ"; + self.countryCode = [NSNumber numberWithInteger:268]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[027]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataTV +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[279]\\d{4,6}" withPossibleNumberPattern:@"\\d{5,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[02-9]\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"20123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:70\\d|90)\\d{4}" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"901234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TV"; + self.countryCode = [NSNumber numberWithInteger:688]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-689]\\d{7,8}|7\\d{7,9}" withPossibleNumberPattern:@"\\d{8,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TW"; + self.countryCode = [NSNumber numberWithInteger:886]; + self.internationalPrefix = @"0(?:0[25679]|19)"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @"#"; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-6]|[78][1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-8])(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"80|9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"70"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(70)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[17]\\d{6,9}|[2-69]\\d{7,9}|8\\d{6,8}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[025-79]|1[0189]|[348][01])|3(?:[0136-9]|[25][01])|4\\d|5(?:[01][01]|[2-9])|6(?:[0-46-8]|5[01])|7(?:[02-79]|[18][01]))\\d{7}|8(?:[1-57]\\d|[689][0-79])\\d{6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"2101234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:9\\d|1(?:2\\d|6[2-9]|8[68]|99))\\d{7}|8[689]8\\d{6}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{4,6}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1900\\d{4,6}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[17]99\\d{4}|69\\d{5,6}|80\\d{5}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"1992000"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[17]99\\d{4}|69\\d{5,6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"1992000"]; + self.codeID = @"VN"; + self.countryCode = [NSNumber numberWithInteger:84]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[17]99"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([17]99)(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"4|8(?:[1-57]|[689][0-79])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([48])(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"2[025-79]|3[0136-9]|5[2-9]|6[0-46-8]|7[02-79]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([235-7]\\d)(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(80)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"69"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(69\\d)(\\d{4,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"2[1348]|3[25]|5[01]|65|7[18]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"([235-7]\\d{2})(\\d{4})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"8[689]8|9"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"1(?:[26]|8[68]|99)"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(1[2689]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"1[89]0"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(1[89]00)(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataUS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:0[1-35-9]|1[02-9]|2[04589]|3[149]|4[08]|5[1-46]|6[0279]|7[026]|8[13])|3(?:0[1-57-9]|1[02-9]|2[0135]|3[014679]|4[67]|5[12]|6[014]|8[056])|4(?:0[124-9]|1[02-579]|2[3-5]|3[0245]|4[0235]|58|69|7[0589]|8[04])|5(?:0[1-57-9]|1[0235-8]|20|3[0149]|4[01]|5[19]|6[1-37]|7[013-5]|8[056])|6(?:0[1-35-9]|1[024-9]|2[03689]|3[016]|4[16]|5[017]|6[0-279]|78|8[12])|7(?:0[1-46-8]|1[02-9]|2[0457]|3[1247]|4[037]|5[47]|6[02359]|7[02-59]|8[156])|8(?:0[1-68]|1[02-8]|28|3[0-25]|4[3578]|5[046-9]|6[02-5]|7[028])|9(?:0[1346-9]|1[02-9]|2[0589]|3[014678]|4[0179]|5[12469]|7[0-3589]|8[0459]))[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2015550123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:0[1-35-9]|1[02-9]|2[04589]|3[149]|4[08]|5[1-46]|6[0279]|7[026]|8[13])|3(?:0[1-57-9]|1[02-9]|2[0135]|3[014679]|4[67]|5[12]|6[014]|8[056])|4(?:0[124-9]|1[02-579]|2[3-5]|3[0245]|4[0235]|58|69|7[0589]|8[04])|5(?:0[1-57-9]|1[0235-8]|20|3[0149]|4[01]|5[19]|6[1-37]|7[013-5]|8[056])|6(?:0[1-35-9]|1[024-9]|2[03689]|3[016]|4[16]|5[017]|6[0-279]|78|8[12])|7(?:0[1-46-8]|1[02-9]|2[0457]|3[1247]|4[037]|5[47]|6[02359]|7[02-59]|8[156])|8(?:0[1-68]|1[02-8]|28|3[0-25]|4[3578]|5[046-9]|6[02-5]|7[028])|9(?:0[1346-9]|1[02-9]|2[0589]|3[014678]|4[0179]|5[12469]|7[0-3589]|8[0459]))[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2015550123"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"US"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"($1) $2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[2-8]\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"222345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[125-9]|7[1-9])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"621234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[08]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:40|6[01])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"840123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"41\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"412345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"TZ"; + self.countryCode = [NSNumber numberWithInteger:255]; + self.internationalPrefix = @"00[056]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[24]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([24]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[67]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([67]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata878 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{11}" withPossibleNumberPattern:@"\\d{12}" withExample:@"101234567890"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"101234567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"101234567890"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"10\\d{10}" withPossibleNumberPattern:@"\\d{12}" withExample:@"101234567890"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:878]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataYE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{6,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:7\\d|[2-68])|2[2-68]|3[2358]|4[2-58]|5[2-6]|6[3-58]|7[24-68])\\d{5}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"1234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[0137]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"712345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"YE"; + self.countryCode = [NSNumber numberWithInteger:967]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-6]|7[24-68]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-7])(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7[0137]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataZA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-79]\\d{8}|8(?:[067]\\d{7}|[1-4]\\d{3,7})" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[0-8]|2[0-378]|3[1-69]|4\\d|5[1346-8])\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"101234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[0-5]|7[0-46-9])\\d{7}|8[1-4]\\d{3,7}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"711234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"86[2-9]\\d{6}|90\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"862345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"860\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"860123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"87\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"871234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"861\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"861123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ZA"; + self.countryCode = [NSNumber numberWithInteger:27]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"860"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(860)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[1-79]|8(?:[0-47]|6[1-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"8[1-4]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8[1-4]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataUY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2489]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{7}|4[2-7]\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"21231234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[1-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"94231234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[05]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[0-8]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9001234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"UY"; + self.countryCode = [NSNumber numberWithInteger:598]; + self.internationalPrefix = @"0(?:1[3-9]\\d|0)"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" int. "; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[24]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"9[1-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]0"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataVU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-57-9]\\d{4,6}" withPossibleNumberPattern:@"\\d{5,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[02-9]\\d|3(?:[5-7]\\d|8[0-8])|48[4-9]|88\\d)\\d{2}" withPossibleNumberPattern:@"\\d{5}" withExample:@"22123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5(?:7[2-5]|[0-689]\\d)|7[013-7]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5912345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[03]\\d{3}|900\\d{4}" withPossibleNumberPattern:@"\\d{5,7}" withExample:@"30123"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"VU"; + self.countryCode = [NSNumber numberWithInteger:678]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[579]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataUZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[679]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6(?:1(?:22|3[124]|4[1-4]|5[123578]|64)|2(?:22|3[0-57-9]|41)|5(?:22|3[3-7]|5[024-8])|6\\d{2}|7(?:[23]\\d|7[69])|9(?:22|4[1-8]|6[135]))|7(?:0(?:5[4-9]|6[0146]|7[12456]|9[135-8])|1[12]\\d|2(?:22|3[1345789]|4[123579]|5[14])|3(?:2\\d|3[1578]|4[1-35-7]|5[1-57]|61)|4(?:2\\d|3[1-579]|7[1-79])|5(?:22|5[1-9]|6[1457])|6(?:22|3[12457]|4[13-8])|9(?:22|5[1-9])))\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"662345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:1(?:2(?:98|2[01])|35[0-4]|50\\d|61[23]|7(?:[01][017]|4\\d|55|9[5-9]))|2(?:11\\d|2(?:[12]1|9[01379])|5(?:[126]\\d|3[0-4])|7\\d{2})|5(?:19[01]|2(?:27|9[26])|30\\d|59\\d|7\\d{2})|6(?:2(?:1[5-9]|2[0367]|38|41|52|60)|3[79]\\d|4(?:56|83)|7(?:[07]\\d|1[017]|3[07]|4[047]|5[057]|67|8[0178]|9[79])|9[0-3]\\d)|7(?:2(?:24|3[237]|4[5-9]|7[15-8])|5(?:7[12]|8[0589])|7(?:0\\d|[39][07])|9(?:0\\d|7[079]))|9(?:2(?:1[1267]|5\\d|3[01]|7[0-4])|5[67]\\d|6(?:2[0-26]|8\\d)|7\\d{2}))\\d{4}|7(?:0\\d{3}|1(?:13[01]|6(?:0[47]|1[67]|66)|71[3-69]|98\\d)|2(?:2(?:2[79]|95)|3(?:2[5-9]|6[0-6])|57\\d|7(?:0\\d|1[17]|2[27]|3[37]|44|5[057]|66|88))|3(?:2(?:1[0-6]|21|3[469]|7[159])|33\\d|5(?:0[0-4]|5[579]|9\\d)|7(?:[0-3579]\\d|4[0467]|6[67]|8[078])|9[4-6]\\d)|4(?:2(?:29|5[0257]|6[0-7]|7[1-57])|5(?:1[0-4]|8\\d|9[5-9])|7(?:0\\d|1[024589]|2[0127]|3[0137]|[46][07]|5[01]|7[5-9]|9[079])|9(?:7[015-9]|[89]\\d))|5(?:112|2(?:0\\d|2[29]|[49]4)|3[1568]\\d|52[6-9]|7(?:0[01578]|1[017]|[23]7|4[047]|[5-7]\\d|8[78]|9[079]))|6(?:2(?:2[1245]|4[2-4])|39\\d|41[179]|5(?:[349]\\d|5[0-2])|7(?:0[017]|[13]\\d|22|44|55|67|88))|9(?:22[128]|3(?:2[0-4]|7\\d)|57[05629]|7(?:2[05-9]|3[37]|4\\d|60|7[2579]|87|9[07])))\\d{4}|9[0-57-9]\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"UZ"; + self.countryCode = [NSNumber numberWithInteger:998]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([679]\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataWS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{4,6}" withPossibleNumberPattern:@"\\d{5,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-5]\\d|6[1-9]|84\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{5,7}" withExample:@"22123"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:60|7[25-7]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"601234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{3}" withPossibleNumberPattern:@"\\d{6}" withExample:@"800123"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"WS"; + self.countryCode = [NSNumber numberWithInteger:685]; + self.internationalPrefix = @"0"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{2})(\\d{3,4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[2-6]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata979 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{9}" withExample:@"123456789"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{9}" withExample:@"123456789"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:979]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataZM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[289]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"21[1-8]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"211234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:5[05]|6\\d|7[1-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"955123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ZM"; + self.countryCode = [NSNumber numberWithInteger:260]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[29]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([29]\\d)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[46]\\d{4}|[01589]\\d{5}" withPossibleNumberPattern:@"\\d{5,6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[2-467]\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"62889"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:@"40123"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[01589]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:@"542011"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AC"; + self.countryCode = [NSNumber numberWithInteger:247]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[346-9]|180)\\d{5}" withPossibleNumberPattern:@"\\d{6,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[78]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:@"712345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[346]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:@"312345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"180[02]\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"18001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:@"912345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AD"; + self.countryCode = [NSNumber numberWithInteger:376]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[346-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(180[02])(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataYT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[268]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"269(?:6[0-4]|50)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"269601234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"639\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"639123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"YT"; + self.countryCode = [NSNumber numberWithInteger:262]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"269|63"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-79]\\d{7,8}|800\\d{2,9}" withPossibleNumberPattern:@"\\d{5,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-4679][2-8]\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"22345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[024-6]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"501234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"400\\d{6}|800\\d{2,9}" withPossibleNumberPattern:@"\\d{5,12}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[02]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700[05]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"700012345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"600[25]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"600212345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AE"; + self.countryCode = [NSNumber numberWithInteger:971]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-4679][2-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-4679])(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[479]0"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([479]00)(\\d)(\\d{5})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"60|8"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([68]00)(\\d{2,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[3-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[35]\\d|49)\\d{6}" withPossibleNumberPattern:@"\\d{6,8}" withExample:@"30123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:03|44|71|[1-356])\\d{6}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"61123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[08]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[0246]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[12]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"82123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70[23]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70223456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BA"; + self.countryCode = [NSNumber numberWithInteger:387]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[3-5]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6[1-356]|[7-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"6[047]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-7]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[25][0-8]|[34][0-4]|6[0-5])[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"234567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[014-9]\\d{7}|2[89]\\d{6})" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AF"; + self.countryCode = [NSNumber numberWithInteger:93]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-7]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"246(?:2(?:2[78]|7[0-4])|4(?:1[024-6]|2\\d|3[2-9])|5(?:20|[34]\\d|54|7[1-3])|6(?:2\\d|38)|7(?:37|57)|9(?:1[89]|63))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2464123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"246(?:2(?:[356]\\d|4[0-57-9]|8[0-79])|45\\d|8(?:[2-5]\\d|83))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2462501234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}|246976\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"24631\\d{5}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2463101234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"246(?:292|41[7-9]|43[01])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2464301234"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BB"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"246"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"268(?:4(?:6[0-38]|84)|56[0-2])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2684601234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"268(?:464|7(?:2[0-9]|64|7[0-689]|8[02-68]))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2684641234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"26848[01]\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2684801234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"26840[69]\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2684061234"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AG"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"268"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-79]\\d{5,9}|1\\d{9}|8[0-7]\\d{4,8}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:550\\d|7(?:1[0-267]|2[0-289]|3[0-29]|[46][01]|5[1-3]|7[017]|91)|8(?:0[125]|[139][1-6]|2[0157-9]|6[1-35]|7[1-5]|8[1-8]|90)|9(?:0[0-2]|1[0-4]|2[568]|3[3-6]|5[5-7]|6[0167]|7[15]|8[0146-8]))\\d{4}|3(?:12?[5-7]\\d{2}|0(?:2(?:[025-79]\\d|[348]\\d{1,2})|3(?:[2-4]\\d|[56]\\d?))|2(?:1\\d{2}|2(?:[12]\\d|[35]\\d{1,2}|4\\d?))|3(?:1\\d{2}|2(?:[2356]\\d|4\\d{1,2}))|4(?:1\\d{2}|2(?:2\\d{1,2}|[47]|5\\d{2}))|5(?:1\\d{2}|29)|[67]1\\d{2}|8(?:1\\d{2}|2(?:2\\d{2}|3|4\\d)))\\d{3}|4(?:0(?:2(?:[09]\\d|7)|33\\d{2})|1\\d{3}|2(?:1\\d{2}|2(?:[25]\\d?|[348]\\d|[67]\\d{1,2}))|3(?:1\\d{2}(?:\\d{2})?|2(?:[045]\\d|[236-9]\\d{1,2})|32\\d{2})|4(?:[18]\\d{2}|2(?:[2-46]\\d{2}|3)|5[25]\\d{2})|5(?:1\\d{2}|2(?:3\\d|5))|6(?:[18]\\d{2}|2(?:3(?:\\d{2})?|[46]\\d{1,2}|5\\d{2}|7\\d)|5(?:3\\d?|4\\d|[57]\\d{1,2}|6\\d{2}|8))|71\\d{2}|8(?:[18]\\d{2}|23\\d{2}|54\\d{2})|9(?:[18]\\d{2}|2[2-5]\\d{2}|53\\d{1,2}))\\d{3}|5(?:02[03489]\\d{2}|1\\d{2}|2(?:1\\d{2}|2(?:2(?:\\d{2})?|[457]\\d{2}))|3(?:1\\d{2}|2(?:[37](?:\\d{2})?|[569]\\d{2}))|4(?:1\\d{2}|2[46]\\d{2})|5(?:1\\d{2}|26\\d{1,2})|6(?:[18]\\d{2}|2|53\\d{2})|7(?:1|24)\\d{2}|8(?:1|26)\\d{2}|91\\d{2})\\d{3}|6(?:0(?:1\\d{2}|2(?:3\\d{2}|4\\d{1,2}))|2(?:2[2-5]\\d{2}|5(?:[3-5]\\d{2}|7)|8\\d{2})|3(?:1|2[3478])\\d{2}|4(?:1|2[34])\\d{2}|5(?:1|2[47])\\d{2}|6(?:[18]\\d{2}|6(?:2(?:2\\d|[34]\\d{2})|5(?:[24]\\d{2}|3\\d|5\\d{1,2})))|72[2-5]\\d{2}|8(?:1\\d{2}|2[2-5]\\d{2})|9(?:1\\d{2}|2[2-6]\\d{2}))\\d{3}|7(?:(?:02|[3-589]1|6[12]|72[24])\\d{2}|21\\d{3}|32)\\d{3}|8(?:(?:4[12]|[5-7]2|1\\d?)|(?:0|3[12]|[5-7]1|217)\\d)\\d{4}|9(?:[35]1|(?:[024]2|81)\\d|(?:1|[24]1)\\d{2})\\d{3}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"27111234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[13-9]\\d|(?:3[78]|44)[02-9]|6(?:44|6[02-9]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1812345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[03]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"96(?:0[49]|1[0-4]|6[69])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9604123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BD"; + self.countryCode = [NSNumber numberWithInteger:880]; + self.internationalPrefix = @"00[12]?"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{7,8})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[3-79]1"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4,6})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1|3(?:0|[2-58]2)|4(?:0|[25]2|3[23]|[4689][25])|5(?:[02-578]2|6[25])|6(?:[0347-9]2|[26][25])|7[02-9]2|8(?:[023][23]|[4-7]2)|9(?:[02][23]|[458]2|6[016])"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3,6})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[3-79][2-9]|8"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,7})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2644(?:6[12]|9[78])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2644612345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"264(?:235|476|5(?:3[6-9]|8[1-4])|7(?:29|72))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2642351234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AI"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"264"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[0-69]|[23][2-8]|4[23]|5\\d|6[013-57-9]|71|8[1-79]|9[2-4])\\d{6}|80[2-8]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4(?:6[0135-8]|[79]\\d|8[3-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"470123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:70[2-467]|90[0-79])\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"78\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"78123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BE"; + self.countryCode = [NSNumber numberWithInteger:32]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"4[6-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[23]|4[23]|9[2-4]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[156]|7[018]|8(?:0[1-9]|[1-79])"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"(?:80|9)0"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{9}|3\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:04|[23]6|[48]9|50)|3(?:06|43|65)|4(?:03|1[68]|3[178]|50)|5(?:06|1[49]|48|79|8[17])|6(?:0[04]|13|22|39|47)|7(?:0[59]|78|8[02])|8(?:[06]7|19|25|73)|90[25])[2-9]\\d{6}|310\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2042345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:04|[23]6|[48]9|50)|3(?:06|43|65)|4(?:03|1[68]|3[178]|50)|5(?:06|1[49]|48|79|8[17])|6(?:0[04]|13|22|39|47)|7(?:0[59]|78|8[02])|8(?:[06]7|19|25|73)|90[25])[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2042345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}|310\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CA"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[267]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:0(?:49|5[23]|9[016-9])|4(?:4[569]|5[4-6]|7[0179])|5(?:[34]\\d|50))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20491234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:[0-689]\\d|7[0-5])\\d{5}|7\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BF"; + self.countryCode = [NSNumber numberWithInteger:226]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23567]\\d{5,7}|[489]\\d{6,8}" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[0-8]\\d{5,6}|9\\d{4,6})|(?:[36]\\d|5[1-9]|8[1-6]|9[1-7])\\d{5,6}|(?:4(?:[124-7]\\d|3[1-6])|7(?:0[1-9]|[1-9]\\d))\\d{4,5}" withPossibleNumberPattern:@"\\d{5,8}" withExample:@"2123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:8[7-9]\\d|9(?:8\\d|99))\\d{6}|4(?:3[0789]|8\\d)\\d{5}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"48123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{5}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"70012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BG"; + self.countryCode = [NSNumber numberWithInteger:359]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"29"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(2)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"43[124-7]|70[1-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"43[124-7]|70[1-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[78]00"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"999"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"[356]|4[124-7]|7[1-9]|8[1-6]|9[1-7]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2,3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"48|8[7-9]|9[08]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataZW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[012457-9]\\d{3,8}|6(?:[14]\\d{7}|\\d{4}))|[13-79]\\d{4,9}|8[06]\\d{8}" withPossibleNumberPattern:@"\\d{3,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:0(?:4\\d|5\\d{2})|2[278]\\d|48\\d|7(?:[1-7]\\d|[089]\\d{2})|8(?:[2-57-9]|[146]\\d{2})|98)|3(?:08|17|3[78]|7(?:[19]|[56]\\d)|8[37]|98)|5[15][78]|6(?:28\\d{2}|[36]7|75\\d|[69]8|8(?:7\\d|8)))\\d{3}|(?:2(?:1[39]|2[0157]|6[14]|7[35]|84)|329)\\d{7}|(?:1(?:3\\d{2}|9\\d|[4-8])|2(?:0\\d{2}|[569]\\d)|3(?:[26]|[013459]\\d)|5(?:0|5\\d{2}|[689]\\d)|6(?:[39]|[01246]\\d|[78]\\d{2}))\\d{3}|(?:29\\d|39|54)\\d{6}|(?:(?:25|54)83|2582\\d)\\d{3}|(?:4\\d{6,7}|9[2-9]\\d{4,5})" withPossibleNumberPattern:@"\\d{3,10}" withExample:@"1312345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[1378]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"711234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"86(?:1[12]|30|44|55|77|8[367]|99)\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8686123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ZW"; + self.countryCode = [NSNumber numberWithInteger:263]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"4|9[2-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([49])(\\d{3})(\\d{2,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"86[24]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(86\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"2(?:0[45]|2[278]|[49]8|[78])|3(?:08|17|3[78]|7[1569]|8[37]|98)|5[15][78]|6(?:[29]8|[38]7|6[78]|75|[89]8)"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([2356]\\d{2})(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"2(?:1[39]|2[0157]|6[14]|7[35]|84)|329"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"1[3-9]|2[0569]|3[0-69]|5[05689]|6[0-46-9]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"([1-356]\\d)(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"[23]9|54"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"([235]\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"(?:25|54)8"]; + [numberFormats7_patternArray addObject:@"258[23]|5483"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"([25]\\d{3})(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"86"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-57]\\d{7}|6\\d{8}|8\\d{5,7}|9\\d{5}" withPossibleNumberPattern:@"\\d{5,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:[168][1-9]|[247]\\d|9[1-7])|3(?:1[1-3]|[2-6]\\d|[79][1-8]|8[1-9])|4\\d{2}|5(?:1[1-4]|[2-578]\\d|6[1-5]|9[1-7])|8(?:[19][1-5]|[2-6]\\d|[78][1-7]))\\d{5}" withPossibleNumberPattern:@"\\d{5,8}" withExample:@"22345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[6-9]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"661234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{3}" withPossibleNumberPattern:@"\\d{6}" withExample:@"900123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"808\\d{3}" withPossibleNumberPattern:@"\\d{6}" withExample:@"808123"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AL"; + self.countryCode = [NSNumber numberWithInteger:355]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"4[0-6]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(4)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(6[6-9])(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[2358][2-5]|4[7-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[235][16-9]|8[016-9]|[79]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1458]\\d{5,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89162\\d{4}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"891621234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"14(?:5\\d|71)\\d{5}|4(?:[0-2]\\d|3[0-57-9]|4[47-9]|5[0-25-9]|6[6-9]|7[02-9]|8[147-9]|9[017-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"412345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"180(?:0\\d{3}|2)\\d{3}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"190[0126]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"13(?:00\\d{2})?\\d{4}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1300123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"500\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"500123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"550\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"550123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CC"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = @"(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]"; + self.preferredInternationalPrefix = @"0011"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[136-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:3[1356]|6[0156]|7\\d)\\d|6(?:1[16]\\d|500|6(?:0\\d|3[12]|44|7[7-9])|9[69][69])|7(?:1(?:11|78)|7\\d{2}))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"17001234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:[1-4679]\\d|5[013-69]|8[0-47-9])\\d|6(?:3(?:00|33|6[16])|6(?:[69]\\d|3[03-9]|7[0-6])))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"36001234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:87|9[014578])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"84\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"84123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BH"; + self.countryCode = [NSNumber numberWithInteger:973]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{7}" withPossibleNumberPattern:@"\\d{5,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[01]\\d|2(?:2[2-46]|3[1-8]|4[2-69]|5[2-7]|6[1-9]|8[1-7])|3[12]2|47\\d)\\d{5}" withPossibleNumberPattern:@"\\d{5,8}" withExample:@"10123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4[139]|55|77|9[1-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"77123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[016]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[1-4]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80112345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60[2-6]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"60271234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AM"; + self.countryCode = [NSNumber numberWithInteger:374]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1|47"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"4[139]|[5-7]|9[1-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[23]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8|90"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-6]\\d{6}|[18]\\d{6,8}|9\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:2\\d{7}|\\d{6})|[2-6]\\d{6}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"1234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:[0-2459]\\d{2}|8)\\d{5}|9[7-9]\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"991234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CD"; + self.countryCode = [NSNumber numberWithInteger:243]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"12"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8[0-2459]|9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"88"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[1-6]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[267]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"22\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:29|6[189]|7[124-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"79561234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BI"; + self.countryCode = [NSNumber numberWithInteger:257]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBJ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2689]\\d{7}|7\\d{3}" withPossibleNumberPattern:@"\\d{4,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:02|1[037]|2[45]|3[68])\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20211234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[1-8]|9[03-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90011234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[3-5]\\d{2}" withPossibleNumberPattern:@"\\d{4}" withExample:@"7312"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"857[58]\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"85751234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"81\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BJ"; + self.countryCode = [NSNumber numberWithInteger:229]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[29]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d(?:[26-9]\\d|\\d[26-9])\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"222123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[1-49]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"923123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AO"; + self.countryCode = [NSNumber numberWithInteger:244]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[278]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[12]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21612345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[0257]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8776\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"87761234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CF"; + self.countryCode = [NSNumber numberWithInteger:236]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[028]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"222[1-589]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"222123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0[14-6]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"061234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CG"; + self.countryCode = [NSNumber numberWithInteger:242]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[02]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataBL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"590(?:2[7-9]|5[12]|87)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"590271234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"690(?:0[0-7]|[1-9]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"690301234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BL"; + self.countryCode = [NSNumber numberWithInteger:590]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata800 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:800]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataCH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{8}|860\\d{9}" withPossibleNumberPattern:@"\\d{9}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[12467]|3[1-4]|4[134]|5[256]|6[12]|[7-9]1)\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[5-9]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"781234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[016]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"84[0248]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"840123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"878\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"878123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"74[0248]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"740123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5[18]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"581234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"860\\d{9}" withPossibleNumberPattern:@"\\d{12}" withExample:@"860123456789"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CH"; + self.countryCode = [NSNumber numberWithInteger:41]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-7]|[89]1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-9]\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8[047]|90"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"860"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[4589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"441(?:2(?:02|23|61|[3479]\\d)|[46]\\d{2}|5(?:4\\d|60|89)|824)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"4412345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"441(?:[37]\\d|5[0-39])\\d{5}" withPossibleNumberPattern:@"\\d{10}" withExample:@"4413701234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BM"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"441"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"11\\d{8}|[2368]\\d{9}|9\\d{10}" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"11\\d{8}|(?:2(?:2(?:[013]\\d|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[067]\\d)|4(?:7[3-8]|9\\d)|6(?:[01346]\\d|2[24-6]|5[15-8])|80\\d|9(?:[0124789]\\d|3[1-6]|5[234]|6[2-46]))|3(?:3(?:2[79]|6\\d|8[2578])|4(?:[78]\\d|0[0124-9]|[1-35]\\d|4[24-7]|6[02-9]|9[123678])|5(?:[138]\\d|2[1245]|4[1-9]|6[2-4]|7[1-6])|6[24]\\d|7(?:[0469]\\d|1[1568]|2[013-9]|3[145]|5[14-8]|7[2-57]|8[0-24-9])|8(?:[013578]\\d|2[15-7]|4[13-6]|6[1-357-9]|9[124]))|670\\d)\\d{6}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"675\\d{7}|9(?:11[2-9]\\d{7}|(?:2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[12358]|5[138]|6[24]|7[069]|8[013578]))[2-9]\\d{6}|\\d{4}[2-9]\\d{5})" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"91123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60[04579]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"810\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8101234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"810\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8101234567"]; + self.codeID = @"AR"; + self.countryCode = [NSNumber numberWithInteger:54]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[0-24-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:[069]|1[1568]|2[15]|3[145]|4[13]|5[14-8]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))?15)?"; + self.nationalPrefixTransformRule = @"9$1"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[68]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([68]\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[2-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[2-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"911"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(9)(11)(\\d{4})(\\d{4})" withFormat:@"$2 15-$3-$4" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"9(?:2[234689]|3[3-8])"]; + [numberFormats5_patternArray addObject:@"9(?:2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[1-358]|5[138]|6[24]|7[069]|8[013578]))"]; + [numberFormats5_patternArray addObject:@"9(?:2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3[456]|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45])))"]; + [numberFormats5_patternArray addObject:@"9(?:2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3(?:4|5[014]|6[1239])|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45])))"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$2 15-$3-$4" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"9[23]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$2 15-$3-$4" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(11)(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[1-358]|5[138]|6[24]|7[069]|8[013578])"]; + [numberFormats8_patternArray addObject:@"2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3[456]|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45]))"]; + [numberFormats8_patternArray addObject:@"2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3(?:4|5[014]|6[1239])|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45]))"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"[23]"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"1[012]|911"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[68]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([68]\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"911"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(9)(11)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3-$4" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"9(?:2[234689]|3[3-8])"]; + [intlNumberFormats2_patternArray addObject:@"9(?:2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[1-358]|5[138]|6[24]|7[069]|8[013578]))"]; + [intlNumberFormats2_patternArray addObject:@"9(?:2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3[456]|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45])))"]; + [intlNumberFormats2_patternArray addObject:@"9(?:2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3(?:4|5[014]|6[1239])|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45])))"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3-$4" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"9[23]"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3-$4" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"1"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(11)(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[1-358]|5[138]|6[24]|7[069]|8[013578])"]; + [intlNumberFormats5_patternArray addObject:@"2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3[456]|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45]))"]; + [intlNumberFormats5_patternArray addObject:@"2(?:2(?:0[013-9]|[13])|3(?:0[013-9]|[67])|49|6(?:[0136]|4[0-59])|8|9(?:[19]|44|7[013-9]|8[14]))|3(?:36|4(?:[12]|3(?:4|5[014]|6[1239])|[58]4)|5(?:1|3[0-24-689]|8[46])|6|7[069]|8(?:[01]|34|[578][45]))"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"[23]"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[02-8]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:0[023]|1[02357]|[23][045]|4[03-5])|3(?:0[06]|1[069]|[2-4][07]|5[09]|6[08]))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:0[1-9]|4\\d|5[14-9]|6[015-79]|7[578]|87)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"01234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CI"; + self.countryCode = [NSNumber numberWithInteger:225]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataBN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-578]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[013-9]\\d|2[0-7])\\d{4}|[3-5]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"22[89]\\d{4}|[78]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BN"; + self.countryCode = [NSNumber numberWithInteger:673]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-578]\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataDE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-35-9]\\d{3,14}|4(?:[0-8]\\d{4,12}|9(?:[0-37]\\d|4(?:[1-35-8]|4\\d?)|5\\d{1,2}|6[1-8]\\d?)\\d{2,8})" withPossibleNumberPattern:@"\\d{2,15}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[246]\\d{5,13}|3(?:0\\d{3,13}|2\\d{9}|[3-9]\\d{4,13})|5(?:0[2-8]|[1256]\\d|[38][0-8]|4\\d{0,2}|[79][0-7])\\d{3,11}|7(?:0[2-8]|[1-9]\\d)\\d{3,10}|8(?:0[2-9]|[1-9]\\d)\\d{3,10}|9(?:0[6-9]\\d{3,10}|1\\d{4,12}|[2-9]\\d{4,11})" withPossibleNumberPattern:@"\\d{2,15}" withExample:@"30123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:5[0-25-9]\\d{8}|6[023]\\d{7,8}|7(?:[0-57-9]\\d?|6\\d)\\d{7})" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"15123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7,12}" withPossibleNumberPattern:@"\\d{10,15}" withExample:@"8001234567890"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"137[7-9]\\d{6}|900(?:[135]\\d{6}|9\\d{7})" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:3(?:7[1-6]\\d{6}|8\\d{4})|80\\d{5,11})" withPossibleNumberPattern:@"\\d{7,14}" withExample:@"18012345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{8}" withPossibleNumberPattern:@"\\d{11}" withExample:@"70012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"16(?:4\\d{1,10}|[89]\\d{1,11})" withPossibleNumberPattern:@"\\d{4,14}" withExample:@"16412345"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18(?:1\\d{5,11}|[2-9]\\d{8})" withPossibleNumberPattern:@"\\d{8,14}" withExample:@"18500123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:5(?:(?:2\\d55|7\\d99|9\\d33)\\d{7}|(?:[034568]00|113)\\d{8})|6(?:013|255|399)\\d{7,8}|7(?:[015]13|[234]55|[69]33|[78]99)\\d{7,8})" withPossibleNumberPattern:@"\\d{12,13}" withExample:@"177991234567"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DE"; + self.countryCode = [NSNumber numberWithInteger:49]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1[67]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d{2})(\\d{7,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"15[0568]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(15\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"15"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d{3})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"3[02]|40|[68]9"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3,11})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"2(?:\\d1|0[2389]|1[24]|28|34)|3(?:[3-9][15]|40)|[4-8][1-9]1|9(?:06|[1-9]1)"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,11})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"[24-6]|[7-9](?:\\d[1-9]|[1-9]\\d)|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])"]; + [numberFormats5_patternArray addObject:@"[24-6]|[7-9](?:\\d[1-9]|[1-9]\\d)|3(?:3(?:0[1-467]|2[127-9]|3[124578]|[46][1246]|7[1257-9]|8[1256]|9[145])|4(?:2[135]|3[1357]|4[13578]|6[1246]|7[1356]|9[1346])|5(?:0[14]|2[1-3589]|3[1357]|4[1246]|6[1-4]|7[1346]|8[13568]|9[1246])|6(?:0[356]|2[1-489]|3[124-6]|4[1347]|6[13]|7[12579]|8[1-356]|9[135])|7(?:2[1-7]|3[1357]|4[145]|6[1-5]|7[1-4])|8(?:21|3[1468]|4[1347]|6[0135-9]|7[1467]|8[136])|9(?:0[12479]|2[1358]|3[1357]|4[134679]|6[1-9]|7[136]|8[147]|9[1468]))"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2,11})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(3\\d{4})(\\d{1,10})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{7,12})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"(?:18|90)0|137"]; + [numberFormats8_patternArray addObject:@"1(?:37|80)|900[1359]"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d)(\\d{4,10})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"181"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d{2})(\\d{5,11})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"185"]; + [numberFormats10_patternArray addObject:@"1850"]; + [numberFormats10_patternArray addObject:@"18500"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(18\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + + NSMutableArray *numberFormats11_patternArray = [[NSMutableArray alloc] init]; + [numberFormats11_patternArray addObject:@"18[68]"]; + NBNumberFormat *numberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(18\\d{2})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats11_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats11]; + + NSMutableArray *numberFormats12_patternArray = [[NSMutableArray alloc] init]; + [numberFormats12_patternArray addObject:@"18[2-579]"]; + NBNumberFormat *numberFormats12 = [[NBNumberFormat alloc] initWithPattern:@"(18\\d)(\\d{8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats12_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats12]; + + NSMutableArray *numberFormats13_patternArray = [[NSMutableArray alloc] init]; + [numberFormats13_patternArray addObject:@"700"]; + NBNumberFormat *numberFormats13 = [[NBNumberFormat alloc] initWithPattern:@"(700)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats13_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats13]; + + NSMutableArray *numberFormats14_patternArray = [[NSMutableArray alloc] init]; + [numberFormats14_patternArray addObject:@"138"]; + NBNumberFormat *numberFormats14 = [[NBNumberFormat alloc] initWithPattern:@"(138)(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats14_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats14]; + + NSMutableArray *numberFormats15_patternArray = [[NSMutableArray alloc] init]; + [numberFormats15_patternArray addObject:@"15[013-68]"]; + NBNumberFormat *numberFormats15 = [[NBNumberFormat alloc] initWithPattern:@"(15[013-68])(\\d{2})(\\d{8})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats15_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats15]; + + NSMutableArray *numberFormats16_patternArray = [[NSMutableArray alloc] init]; + [numberFormats16_patternArray addObject:@"15[279]"]; + NBNumberFormat *numberFormats16 = [[NBNumberFormat alloc] initWithPattern:@"(15[279]\\d)(\\d{2})(\\d{7})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats16_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats16]; + + NSMutableArray *numberFormats17_patternArray = [[NSMutableArray alloc] init]; + [numberFormats17_patternArray addObject:@"1(?:6[023]|7)"]; + NBNumberFormat *numberFormats17 = [[NBNumberFormat alloc] initWithPattern:@"(1[67]\\d)(\\d{2})(\\d{7,8})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats17_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats17]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6846(?:22|33|44|55|77|88|9[19])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6846221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"684(?:2(?:5[2468]|72)|7(?:3[13]|70))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6847331234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AS"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"684"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23467]\\d{7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:2\\d{2}|5(?:11|[258]\\d|9[67])|6(?:12|2\\d|9[34])|8(?:2[34]|39|62))|3(?:3\\d{2}|4(?:6\\d|8[24])|8(?:25|42|5[257]|86|9[25])|9(?:2\\d|3[234]|4[248]|5[24]|6[2-6]|7\\d))|4(?:4\\d{2}|6(?:11|[24689]\\d|72)))\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BO"; + self.countryCode = [NSNumber numberWithInteger:591]; + self.internationalPrefix = @"00(1\\d)?"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0(1\\d)?"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[234]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([234])(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[67]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([67]\\d{7})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{3,12}" withPossibleNumberPattern:@"\\d{3,13}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{3,12}|(?:2(?:1[467]|2[13-8]|5[2357]|6[1-46-8]|7[1-8]|8[124-7]|9[1458])|3(?:1[1-8]|3[23568]|4[5-7]|5[1378]|6[1-38]|8[3-68])|4(?:2[1-8]|35|63|7[1368]|8[2457])|5(?:12|2[1-8]|3[357]|4[147]|5[12578]|6[37])|6(?:13|2[1-47]|4[1-35-8]|5[468]|62)|7(?:2[1-8]|3[25]|4[13478]|5[68]|6[16-8]|7[1-6]|9[45]))\\d{3,10}" withPossibleNumberPattern:@"\\d{3,13}" withExample:@"1234567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:5[0-3579]|6[013-9]|[7-9]\\d)\\d{4,10}" withPossibleNumberPattern:@"\\d{7,13}" withExample:@"664123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6,10}" withPossibleNumberPattern:@"\\d{9,13}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:9(?:0[01]|3[019]))\\d{6,10}" withPossibleNumberPattern:@"\\d{9,13}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:10\\d|2(?:[01]\\d|8\\d?))\\d{5,9}" withPossibleNumberPattern:@"\\d{8,13}" withExample:@"810123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"780\\d{6,10}" withPossibleNumberPattern:@"\\d{9,13}" withExample:@"780123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:(?:0[1-9]|17)\\d{2,10}|[79]\\d{3,11})|720\\d{6,10}" withPossibleNumberPattern:@"\\d{5,13}" withExample:@"50123"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AT"; + self.countryCode = [NSNumber numberWithInteger:43]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"116"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(116\\d{3})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3,12})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"5[079]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d)(\\d{3,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"5[079]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"5[079]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(5\\d)(\\d{4})(\\d{4,7})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"316|46|51|732|6(?:5[0-3579]|[6-9])|7(?:[28]0)|[89]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,10})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"2|3(?:1[1-578]|[3-8])|4[2378]|5[2-6]|6(?:[12]|4[1-9]|5[468])|7(?:2[1-8]|35|4[1-8]|[5-79])"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3,9})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2\\d|3[13-7]|4[1-5])\\d{3}" withPossibleNumberPattern:@"\\d{5}" withExample:@"21234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5-8]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:@"71234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CK"; + self.countryCode = [NSNumber numberWithInteger:682]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-578]\\d{5,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[237]\\d{8}|8(?:[6-8]\\d{3}|9(?:[02-9]\\d{2}|1(?:[0-57-9]\\d|6[0135-9])))\\d{4}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"14(?:5\\d|71)\\d{5}|4(?:[0-3]\\d|4[47-9]|5[0-25-9]|6[6-9]|7[02-9]|8[147-9]|9[017-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"412345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"180(?:0\\d{3}|2)\\d{3}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"19(?:0[0126]\\d|[679])\\d{5}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"13(?:00\\d{3}|45[0-4]|\\d)\\d{3}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1300123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"500\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"500123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"550\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"550123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"16\\d{3,7}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"1612345"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:3(?:00\\d{3}|45[0-4]|\\d)\\d{3}|80(?:0\\d{6}|2\\d{3}))" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1300123456"]; + self.codeID = @"AU"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = @"(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]"; + self.preferredInternationalPrefix = @"0011"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2378]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2378])(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[45]|14"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"16"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(16)(\\d{3})(\\d{2,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1(?:[38]0|90)"]; + [numberFormats3_patternArray addObject:@"1(?:[38]00|90)"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1[389]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"180"]; + [numberFormats4_patternArray addObject:@"1802"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(180)(2\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"19[13]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(19\\d)(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"19[679]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(19\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"13[1-9]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(13)(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-9]|600|123)\\d{7,8}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:1962\\d{4}|2\\d{7}|32[0-2]\\d{5})|(?:3[2-5]|[47][1-35]|5[1-3578]|6[13-57])\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"221234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[4-9]\\d{7}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"961234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}|1230\\d{7}" withPossibleNumberPattern:@"\\d{9,11}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"600\\d{7,8}" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"6001234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"44\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"441234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"600\\d{7,8}" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"6001234567"]; + self.codeID = @"CL"; + self.countryCode = [NSNumber numberWithInteger:56]; + self.internationalPrefix = @"(?:0|1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))0"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0|(1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2[23]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[357]|4[1-35]|6[13-57]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"44"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(44)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"60|8"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([68]00)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"60"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(600)(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(1230)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"219"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"[1-9]"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4,5})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"2[23]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"[357]|4[1-35]|6[13-57]"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"44"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(44)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"60|8"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"([68]00)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"60"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(600)(\\d{3})(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"1"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(1230)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + + NSMutableArray *intlNumberFormats7_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats7_patternArray addObject:@"219"]; + NBNumberFormat *intlNumberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats7_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC ($1)"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats7]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataEC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{9,10}|[2-8]\\d{7}|9\\d{8}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-7][2-7]\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:39|[45][89]|[67][7-9]|[89]\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"991234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{6,7}" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"18001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-7]890\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"28901234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"EC"; + self.countryCode = [NSNumber numberWithInteger:593]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[247]|[356][2-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1800)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[247]|[356][2-8]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"9"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"1"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1800)(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBQ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[347]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:318[023]|416[023]|7(?:1[578]|50)\\d)\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7151234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:318[14-68]|416[15-9]|7(?:0[01]|7[07]|[89]\\d)\\d)\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3181234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BQ"; + self.countryCode = [NSNumber numberWithInteger:599]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2368]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:22|33|4[23])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"222123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[5-9]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"671234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"88\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CM"; + self.countryCode = [NSNumber numberWithInteger:237]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[26]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([26])(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[23]|88"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{2})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-46-9]\\d{7,10}|5\\d{8,9}" withPossibleNumberPattern:@"\\d{8,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[14689][1-9]|2[12478]|3[1-578]|5[1-5]|7[13-579])[2-5]\\d{7}" withPossibleNumberPattern:@"\\d{8,11}" withExample:@"1123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1[1-9](?:7|9\\d)\\d{7}|(?:2[12478]|3[1-578]|[689][1-9]|7[13-579])(?:[6-8]|9\\d?)\\d{7}|(?:4[1-9]|5[1-5])[6-9]\\d{7}" withPossibleNumberPattern:@"\\d{10,11}" withExample:@"11961234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6,7}" withPossibleNumberPattern:@"\\d{8,11}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:300|[59]00\\d?)\\d{6}" withPossibleNumberPattern:@"\\d{8,11}" withExample:@"300123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:300\\d(?:\\d{2})?|40(?:0\\d|20))\\d{4}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"40041234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:300\\d|40(?:0\\d|20))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"40041234"]; + self.codeID = @"BR"; + self.countryCode = [NSNumber numberWithInteger:55]; + self.internationalPrefix = @"00(?:1[245]|2[1-35]|31|4[13]|[56]5|99)"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0(?:(1[245]|2[1-35]|31|4[13]|[56]5|99)(\\d{10,11}))?"; + self.nationalPrefixTransformRule = @"$2"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-9](?:[1-9]|0[1-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"9(?:[1-9]|0[1-9])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[125689]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3,5})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"(?:[1689][1-9]|2[12478]|3[1-578]|7[13-579])9"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0 $CC ($1)"]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[1-9][1-9]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0 $CC ($1)"]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"(?:300|40(?:0|20))"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"[3589]00"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"([3589]00)(\\d{2,3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"(?:[1689][1-9]|2[12478]|3[1-578]|7[13-579])9"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0 $CC ($1)"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"[1-9][1-9]"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0 $CC ($1)"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"(?:300|40(?:0|20))"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"[3589]00"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([3589]00)(\\d{2,3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[25-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:2\\d|8[1-9])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5(?:6\\d|9[2-478])|6(?:[039]0|22|4[01]|6[0-2])|7[34]\\d|9(?:6[45]|9[4-8]))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5601234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"8001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9001234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"28\\d{5}|501\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5011234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AW"; + self.countryCode = [NSNumber numberWithInteger:297]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{6,11}|8[0-357-9]\\d{6,9}|9\\d{7,10}" withPossibleNumberPattern:@"\\d{4,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"21(?:100\\d{2}|95\\d{3,4}|\\d{8,10})|(?:10|2[02-57-9]|3(?:11|7[179])|4(?:[15]1|3[1-35])|5(?:1\\d|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:[57]1|98))(?:100\\d{2}|95\\d{3,4}|\\d{8})|(?:3(?:1[02-9]|35|49|5\\d|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|3[3-9]|5[2-9]|6[4789]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[17]\\d|2[248]|3[04-9]|4[3-6]|5[0-4689]|6[2368]|9[02-9])|8(?:078|1[236-8]|2[5-7]|3\\d|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:100\\d{2}|95\\d{3,4}|\\d{7})|80(?:29|6[03578]|7[018]|81)\\d{4}" withPossibleNumberPattern:@"\\d{4,12}" withExample:@"1012345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:[38]\\d|4[57]|5[0-35-9]|7[0136-8])\\d{8}" withPossibleNumberPattern:@"\\d{11}" withExample:@"13123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:10)?800\\d{7}" withPossibleNumberPattern:@"\\d{10,12}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"16[08]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"16812345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"400\\d{7}|950\\d{7,8}|(?:10|2[0-57-9]|3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[4789]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[3678]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))96\\d{3,4}" withPossibleNumberPattern:@"\\d{7,11}" withExample:@"4001234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4|(?:10)?8)00\\d{7}|950\\d{7,8}" withPossibleNumberPattern:@"\\d{10,12}" withExample:@"4001234567"]; + self.codeID = @"CN"; + self.countryCode = [NSNumber numberWithInteger:86]; + self.internationalPrefix = @"(1(?:[129]\\d{3}|79\\d{2}))?00"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"(1(?:[129]\\d{3}|79\\d{2}))|0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"80[2678]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[48]00"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([48]00)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"100|95"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5,6})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"(?:10|2\\d)[19]"]; + [numberFormats3_patternArray addObject:@"(?:10|2\\d)(?:10|9[56])"]; + [numberFormats3_patternArray addObject:@"(?:10|2\\d)(?:100|9[56])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[3-9]"]; + [numberFormats4_patternArray addObject:@"[3-9]\\d{2}[19]"]; + [numberFormats4_patternArray addObject:@"[3-9]\\d{2}(?:10|9[56])"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"[2-9]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3,4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"21"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(21)(\\d{4})(\\d{4,6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"10[1-9]|2[02-9]"]; + [numberFormats7_patternArray addObject:@"10[1-9]|2[02-9]"]; + [numberFormats7_patternArray addObject:@"10(?:[1-79]|8(?:[1-9]|0[1-9]))|2[02-9]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"([12]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"3(?:1[02-9]|35|49|5|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|[35][2-9]|6[4789]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[04-9]|4[3-6]|6[2368])|8(?:1[236-8]|2[5-7]|3|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"3(?:11|7[179])|4(?:[15]1|3[1-35])|5(?:1|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:[57]1|98)"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"807"]; + [numberFormats10_patternArray addObject:@"8078"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats10]; + + NSMutableArray *numberFormats11_patternArray = [[NSMutableArray alloc] init]; + [numberFormats11_patternArray addObject:@"1[3-578]"]; + NBNumberFormat *numberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats11_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats11]; + + NSMutableArray *numberFormats12_patternArray = [[NSMutableArray alloc] init]; + [numberFormats12_patternArray addObject:@"108"]; + [numberFormats12_patternArray addObject:@"1080"]; + [numberFormats12_patternArray addObject:@"10800"]; + NBNumberFormat *numberFormats12 = [[NBNumberFormat alloc] initWithPattern:@"(10800)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats12_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats12]; + + NSMutableArray *numberFormats13_patternArray = [[NSMutableArray alloc] init]; + [numberFormats13_patternArray addObject:@"950"]; + NBNumberFormat *numberFormats13 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{7,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats13_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats13]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"80[2678]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"[48]00"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([48]00)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"(?:10|2\\d)[19]"]; + [intlNumberFormats2_patternArray addObject:@"(?:10|2\\d)(?:10|9[56])"]; + [intlNumberFormats2_patternArray addObject:@"(?:10|2\\d)(?:100|9[56])"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"[3-9]"]; + [intlNumberFormats3_patternArray addObject:@"[3-9]\\d{2}[19]"]; + [intlNumberFormats3_patternArray addObject:@"[3-9]\\d{2}(?:10|9[56])"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"21"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(21)(\\d{4})(\\d{4,6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + + NSMutableArray *intlNumberFormats5_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats5_patternArray addObject:@"10[1-9]|2[02-9]"]; + [intlNumberFormats5_patternArray addObject:@"10[1-9]|2[02-9]"]; + [intlNumberFormats5_patternArray addObject:@"10(?:[1-79]|8(?:[1-9]|0[1-9]))|2[02-9]"]; + NBNumberFormat *intlNumberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"([12]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats5]; + + NSMutableArray *intlNumberFormats6_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats6_patternArray addObject:@"3(?:1[02-9]|35|49|5|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|[35][2-9]|6[4789]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[04-9]|4[3-6]|6[2368])|8(?:1[236-8]|2[5-7]|3|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])"]; + NBNumberFormat *intlNumberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats6]; + + NSMutableArray *intlNumberFormats7_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats7_patternArray addObject:@"3(?:11|7[179])|4(?:[15]1|3[1-35])|5(?:1|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:[57]1|98)"]; + NBNumberFormat *intlNumberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats7]; + + NSMutableArray *intlNumberFormats8_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats8_patternArray addObject:@"807"]; + [intlNumberFormats8_patternArray addObject:@"8078"]; + NBNumberFormat *intlNumberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats8]; + + NSMutableArray *intlNumberFormats9_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats9_patternArray addObject:@"1[3-578]"]; + NBNumberFormat *intlNumberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats9_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats9]; + + NSMutableArray *intlNumberFormats10_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats10_patternArray addObject:@"108"]; + [intlNumberFormats10_patternArray addObject:@"1080"]; + [intlNumberFormats10_patternArray addObject:@"10800"]; + NBNumberFormat *intlNumberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(10800)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats10_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats10]; + + NSMutableArray *intlNumberFormats11_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats11_patternArray addObject:@"950"]; + NBNumberFormat *intlNumberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{7,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats11_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats11]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataEE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{3,4}|[3-9]\\d{6,7}|800\\d{6,7}" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[23589]|4[3-8]|6\\d|7[1-9]|88)\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5\\d|8[1-5])\\d{6}|5(?:[02]\\d{2}|1(?:[0-8]\\d|95)|5[0-478]\\d|64[0-4]|65[1-589])\\d{3}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"51234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800(?:0\\d{3}|1\\d|[2-9])\\d{3}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:40\\d{2}|900)\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"9001234"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70[0-2]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:2[01245]|3[0-6]|4[1-489]|5[0-59]|6[1-46-9]|7[0-27-9]|8[189]|9[012])\\d{1,2}" withPossibleNumberPattern:@"\\d{4,5}" withExample:@"12123"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{3,4}|800[2-9]\\d{3}" withPossibleNumberPattern:@"\\d{4,7}" withExample:@"8002123"]; + self.codeID = @"EE"; + self.countryCode = [NSNumber numberWithInteger:372]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[369]|4[3-8]|5(?:[0-2]|5[0-478]|6[45])|7[1-9]"]; + [numberFormats0_patternArray addObject:@"[369]|4[3-8]|5(?:[02]|1(?:[0-8]|95)|5[0-478]|6(?:4[0-4]|5[1-589]))|7[1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([3-79]\\d{2})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"70"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(70)(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"800"]; + [numberFormats2_patternArray addObject:@"8000"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(8000)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"40|5|8(?:00|[1-5])"]; + [numberFormats3_patternArray addObject:@"40|5|8(?:00[1-9]|[1-5])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([458]\\d{3})(\\d{3,4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"242(?:3(?:02|[236][1-9]|4[0-24-9]|5[0-68]|7[3467]|8[0-4]|9[2-467])|461|502|6(?:0[1-3]|12|7[67]|8[78]|9[89])|7(?:02|88))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"2423456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"242(?:3(?:5[79]|[79]5)|4(?:[2-4][1-9]|5[1-8]|6[2-8]|7\\d|81)|5(?:2[45]|3[35]|44|5[1-9]|65|77)|6[34]6|727)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2423591234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"242300\\d{4}|8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BS"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"242"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataDJ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[27]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:1[2-5]|7[45])\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21360003"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"77[0-26-8]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"77831001"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DJ"; + self.countryCode = [NSNumber numberWithInteger:253]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[135]\\d{5,9}|[27]\\d{4,9}|4\\d{5,10}|6\\d{7,8}|8\\d{6,9}" withPossibleNumberPattern:@"\\d{5,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18[1-8]\\d{3,9}" withPossibleNumberPattern:@"\\d{6,12}" withExample:@"1812345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4\\d{5,10}|50\\d{4,8}" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"412345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4,7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]00\\d{5,6}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"600123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]0\\d{4,8}|2(?:0(?:[016-8]\\d{3,7}|[2-59]\\d{2,7})|9\\d{4,8})|60(?:[12]\\d{5,6}|6\\d{7})|7(?:1\\d{7}|3\\d{8}|5[03-9]\\d{2,7})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"10112345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]00\\d{3,7}|2(?:0(?:0\\d{3,7}|2[023]\\d{1,6}|9[89]\\d{1,6}))|60(?:[12]\\d{5,6}|6\\d{7})|7(?:1\\d{7}|3\\d{8}|5[03-9]\\d{2,7})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"100123"]; + self.codeID = @"AX"; + self.countryCode = [NSNumber numberWithInteger:358]; + self.internationalPrefix = @"00|99[049]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[13]\\d{0,3}|[24-8])\\d{7}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[124-8][2-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:0[0-5]|1\\d|2[0-2]|5[01])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"3211234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"18001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"19(?:0[01]|4[78])\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"19001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CO"; + self.countryCode = [NSNumber numberWithInteger:57]; + self.internationalPrefix = @"00(?:4(?:[14]4|56)|[579])"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0([3579]|4(?:44|56))?"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1(?:8[2-9]|9[0-3]|[2-7])|[24-8]"]; + [numberFormats0_patternArray addObject:@"1(?:8[2-9]|9(?:09|[1-3])|[2-7])|[24-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:80|9[04])"]; + [numberFormats2_patternArray addObject:@"1(?:800|9(?:0[01]|4[78]))"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{7})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"1(?:8[2-9]|9[0-3]|[2-7])|[24-8]"]; + [intlNumberFormats0_patternArray addObject:@"1(?:8[2-9]|9(?:09|[1-3])|[2-7])|[24-8]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"($1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"3"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$CC $1"]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"1(?:80|9[04])"]; + [intlNumberFormats2_patternArray addObject:@"1(?:800|9(?:0[01]|4[78]))"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{7})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-8]\\d{6,7}" withPossibleNumberPattern:@"\\d{6,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[3-6]|[34][5-7]|5[236]|6[2-46]|7[246]|8[2-4])\\d{5}" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"2345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[67]|77)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"17123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BT"; + self.countryCode = [NSNumber numberWithInteger:975]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1|77"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-68]|7[246]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([2-8])(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataDK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-7]\\d|8[126-9]|9[1-36-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"32123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[2-7]\\d|8[126-9]|9[1-36-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DK"; + self.countryCode = [NSNumber numberWithInteger:45]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataEG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{4,9}|[2456]\\d{8}|3\\d{7}|[89]\\d{8,9}" withPossibleNumberPattern:@"\\d{5,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:3[23]\\d|5(?:[23]|9\\d))|2[2-4]\\d{2}|3\\d{2}|4(?:0[2-5]|[578][23]|64)\\d|5(?:0[2-7]|[57][23])\\d|6[24-689]3\\d|8(?:2[2-57]|4[26]|6[237]|8[2-4])\\d|9(?:2[27]|3[24]|52|6[2356]|7[2-4])\\d)\\d{5}|1[69]\\d{3}" withPossibleNumberPattern:@"\\d{5,9}" withExample:@"234567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:0[0-269]|1[0-245]|2[0-278])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1001234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"EG"; + self.countryCode = [NSNumber numberWithInteger:20]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[23]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{7,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[012]|[89]00"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[35]|[4-6]|[89][2-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataAZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1[28]\\d{3}|2(?:02|1[24]|2[2-4]|33|[45]2|6[23])\\d{2}|365(?:[0-46-9]\\d|5[0-35-9]))\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"123123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:36554|(?:4[04]|5[015]|60|7[07])\\d{3})\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"401234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"88\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"881234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900200\\d{3}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900200123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AZ"; + self.countryCode = [NSNumber numberWithInteger:994]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:1[28]|2(?:[45]2|[0-36])|365)"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[4-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataEH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"528[89]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"528812345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:0[0-8]|[12-79]\\d|8[017])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"650123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"891234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"EH"; + self.countryCode = [NSNumber numberWithInteger:212]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"528[89]"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataDM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[57-9]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"767(?:2(?:55|66)|4(?:2[01]|4[0-25-9])|50[0-4]|70[1-3])\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"7674201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"767(?:2(?:[234689]5|7[5-7])|31[5-7]|61[2-7])\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7672251234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DM"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"767"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[24-9]\\d{7,9}" withPossibleNumberPattern:@"\\d{8,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[0-24-7]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:0[01]|7[0-3])\\d{5}|(?:[67][0-3]|8[3-9])\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"83123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[059]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9001234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"210[0-6]\\d{4}|4\\d{7}|5100\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"40001234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CR"; + self.countryCode = [NSNumber numberWithInteger:506]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"(19(?:0[012468]|1[09]|20|66|77|99))"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[24-7]|8[3-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[89]0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-79]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:4[0-48]|6[0-24]|9[0578])|3(?:1[0235-9]|55|[69]\\d|7[01])|4(?:6[03]|7[1267]|9[0-5])|5(?:3[0389]|4[0489]|7[1-47]|88|9[0-49])|6(?:2[1-35]|5[149]|8[067]))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2401234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[1-6]\\d|7[014-8])\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"79[12][01]\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"79101234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BW"; + self.countryCode = [NSNumber numberWithInteger:267]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-6]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(90)(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0?\\d{7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"01\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"01441234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0?[2-7]\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"06031234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GA"; + self.countryCode = [NSNumber numberWithInteger:241]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataDO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:[04]9[2-9]\\d{6}|29(?:2(?:[0-59]\\d|6[04-9]|7[0-27]|8[0237-9])|3(?:[0-35-9]\\d|4[7-9])|[45]\\d{2}|6(?:[0-27-9]\\d|[3-5][1-9]|6[0135-8])|7(?:0[013-9]|[1-37]\\d|4[1-35689]|5[1-4689]|6[1-57-9]|8[1-79]|9[1-8])|8(?:0[146-9]|1[0-48]|[248]\\d|3[1-79]|5[01589]|6[013-68]|7[124-8]|9[0-8])|9(?:[0-24]\\d|3[02-46-9]|5[0-79]|60|7[0169]|8[57-9]|9[02-9]))\\d{4})" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8092345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[024]9[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8092345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DO"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"8[024]9"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-4]\\d{8}|800\\d{3,7}|[89]\\d{9,10}" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1(?:5(?:1[1-5]|[24]\\d|6[2-4]|9[1-7])|6(?:[235]\\d|4[1-7])|7\\d{2})|2(?:1(?:[246]\\d|3[0-35-9]|5[1-9])|2(?:[235]\\d|4[0-8])|3(?:[26]\\d|3[02-79]|4[024-7]|5[03-7])))\\d{5}" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"152450911"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:5[5679]|9[1-9])|33\\d|44\\d)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"294911911"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:0[13]|20\\d)\\d{7}|800\\d{3,7}" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"8011234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:810|902)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9021234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"249\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"249123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:[013]|[12]0)\\d{8}|800\\d{3,7}|902\\d{7}" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"82012345678"]; + self.codeID = @"BY"; + self.countryCode = [NSNumber numberWithInteger:375]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = @"8~10"; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"8?0?"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"17[0-3589]|2[4-9]|[34]"]; + [numberFormats0_patternArray addObject:@"17(?:[02358]|1[0-2]|9[0189])|2[4-9]|[34]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"8 0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1(?:5[24]|6[235]|7[467])|2(?:1[246]|2[25]|3[26])"]; + [numberFormats1_patternArray addObject:@"1(?:5[24]|6(?:2|3[04-9]|5[0346-9])|7(?:[46]|7[37-9]))|2(?:1[246]|2[25]|3[26])"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2-$3-$4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"8 0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:5[169]|6[3-5]|7[179])|2(?:1[35]|2[34]|3[3-5])"]; + [numberFormats2_patternArray addObject:@"1(?:5[169]|6(?:3[1-3]|4|5[125])|7(?:1[3-9]|7[0-24-6]|9[2-7]))|2(?:1[35]|2[34]|3[3-5])"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{3})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"8 0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8[01]|9"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([89]\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"82"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(82\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{2})(\\d{2,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{7,10}" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:0[01378]|3[0189]|4[017]|8[0-46-9]|9[012])\\d{7}|1(?:(?:1(?:3[0-48]|[46][0-4]|5[012789]|7[0-49]|8[01349])|21[0-7]|31[0-8]|[459]1\\d|61[0-46-9]))\\d{6}|1(?:2(?:0[024-9]|2[3-9]|3[3-79]|4[1-689]|[58][02-9]|6[0-4789]|7[013-9]|9\\d)|3(?:0\\d|[25][02-9]|3[02-579]|[468][0-46-9]|7[1235679]|9[24578])|4(?:0[03-9]|[28][02-5789]|[37]\\d|4[02-69]|5[0-8]|[69][0-79])|5(?:0[1235-9]|2[024-9]|3[015689]|4[02-9]|5[03-9]|6\\d|7[0-35-9]|8[0-468]|9[0-5789])|6(?:0[034689]|2[0-35689]|[38][013-9]|4[1-467]|5[0-69]|6[13-9]|7[0-8]|9[0124578])|7(?:0[0246-9]|2\\d|3[023678]|4[03-9]|5[0-46-9]|6[013-9]|7[0-35-9]|8[024-9]|9[02-9])|8(?:0[35-9]|2[1-5789]|3[02-578]|4[0-578]|5[124-9]|6[2-69]|7\\d|8[02-9]|9[02569])|9(?:0[02-589]|2[02-689]|3[1-5789]|4[2-9]|5[0-579]|6[234789]|7[0124578]|8\\d|9[2-57]))\\d{6}|1(?:2(?:0(?:46[1-4]|87[2-9])|545[1-79]|76(?:2\\d|3[1-8]|6[1-6])|9(?:7(?:2[0-4]|3[2-5])|8(?:2[2-8]|7[0-4789]|8[345])))|3(?:638[2-5]|647[23]|8(?:47[04-9]|64[015789]))|4(?:044[1-7]|20(?:2[23]|8\\d)|6(?:0(?:30|5[2-57]|6[1-8]|7[2-8])|140)|8(?:052|87[123]))|5(?:24(?:3[2-79]|6\\d)|276\\d|6(?:26[06-9]|686))|6(?:06(?:4\\d|7[4-79])|295[567]|35[34]\\d|47(?:24|61)|59(?:5[08]|6[67]|74)|955[0-4])|7(?:26(?:6[13-9]|7[0-7])|442\\d|50(?:2[0-3]|[3-68]2|76))|8(?:27[56]\\d|37(?:5[2-5]|8[239])|84(?:3[2-58]))|9(?:0(?:0(?:6[1-8]|85)|52\\d)|3583|4(?:66[1-8]|9(?:2[01]|81))|63(?:23|3[1-4])|9561))\\d{3}|176888[234678]\\d{2}|16977[23]\\d{3}" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"1212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:[1-4]\\d\\d|5(?:0[0-8]|[13-9]\\d|2[0-35-9])|7(?:0[1-9]|[1-7]\\d|8[02-9]|9[0-689])|8(?:[014-9]\\d|[23][0-8])|9(?:[04-9]\\d|1[02-9]|2[0-35-9]|3[0-689]))\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7400123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:0(?:1111|\\d{6,7})|8\\d{7})|500\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{2,3})?" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:87[123]|9(?:[01]\\d|8[2349]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9012345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:4(?:5464\\d|[2-5]\\d{7})|70\\d{7})" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8431234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"56\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5612345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"76(?:0[012]|2[356]|4[0134]|5[49]|6[0-369]|77|81|9[39])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7640123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[0347]|55)\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GB"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" x"; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2|5[56]|7(?:0|6[013-9])"]; + [numberFormats0_patternArray addObject:@"2|5[56]|7(?:0|6(?:[013-9]|2[0-35-9]))"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1(?:1|\\d1)|3|9[018]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1(?:38|5[23]|69|76|94)"]; + [numberFormats2_patternArray addObject:@"1(?:387|5(?:24|39)|697|768|946)"]; + [numberFormats2_patternArray addObject:@"1(?:3873|5(?:242|39[456])|697[347]|768[347]|9467)"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{5})(\\d{4,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"7(?:[1-5789]|62)"]; + [numberFormats4_patternArray addObject:@"7(?:[1-5789]|624)"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(7\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"800"]; + [numberFormats5_patternArray addObject:@"8001"]; + [numberFormats5_patternArray addObject:@"80011"]; + [numberFormats5_patternArray addObject:@"800111"]; + [numberFormats5_patternArray addObject:@"8001111"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"845"]; + [numberFormats6_patternArray addObject:@"8454"]; + [numberFormats6_patternArray addObject:@"84546"]; + [numberFormats6_patternArray addObject:@"845464"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(845)(46)(4\\d)" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"8(?:4[2-5]|7[0-3])"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"80"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"[58]00"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"([58]00)(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-57]\\d{5,7}" withPossibleNumberPattern:@"\\d{4,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[1-4]\\d{5,6}|3(?:1\\d{6}|[23]\\d{4,6})|4(?:[125]\\d{5,6}|[36]\\d{6}|[78]\\d{4,6})|7\\d{6,7}" withPossibleNumberPattern:@"\\d{4,8}" withExample:@"71234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"51234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CU"; + self.countryCode = [NSNumber numberWithInteger:53]; + self.internationalPrefix = @"119"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{6,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-4]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataBZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{6}|0\\d{10}" withPossibleNumberPattern:@"\\d{7}(?:\\d{4})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[23458][02]\\d|7(?:[02]\\d|32))\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2221234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[0-35-7]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6221234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0800\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"08001234123"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BZ"; + self.countryCode = [NSNumber numberWithInteger:501]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(0)(800)(\\d{4})(\\d{3})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataCV +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[259]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:2[1-7]|3[0-8]|4[12]|5[1256]|6\\d|7[1-3]|8[1-5])\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"2211234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:9\\d|59)\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"9911234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CV"; + self.countryCode = [NSNumber numberWithInteger:238]; + self.internationalPrefix = @"0"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadata808 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:808]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataGD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[4589]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"473(?:2(?:3[0-2]|69)|3(?:2[89]|86)|4(?:[06]8|3[5-9]|4[0-49]|5[5-79]|68|73|90)|63[68]|7(?:58|84)|800|938)\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"4732691234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"473(?:4(?:0[2-79]|1[04-9]|20|58)|5(?:2[01]|3[3-8])|901)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"4734031234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GD"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"473"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{4,11}|[2-9]\\d{4,10}" withPossibleNumberPattern:@"\\d{5,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:[3569][1-8]\\d{3,9}|[47]\\d{5,10})|2[1-8]\\d{3,9}|3(?:[1-8]\\d{3,9}|9\\d{4,8})|[5689][1-8]\\d{3,9}" withPossibleNumberPattern:@"\\d{5,12}" withExample:@"1312345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4\\d{5,10}|50\\d{4,8}" withPossibleNumberPattern:@"\\d{6,11}" withExample:@"412345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{4,7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[67]00\\d{5,6}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"600123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]0\\d{4,8}|2(?:0(?:[016-8]\\d{3,7}|[2-59]\\d{2,7})|9\\d{4,8})|60(?:[12]\\d{5,6}|6\\d{7})|7(?:1\\d{7}|3\\d{8}|5[03-9]\\d{2,7})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"10112345"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13]00\\d{3,7}|2(?:0(?:0\\d{3,7}|2[023]\\d{1,6}|9[89]\\d{1,6}))|60(?:[12]\\d{5,6}|6\\d{7})|7(?:1\\d{7}|3\\d{8}|5[03-9]\\d{2,7})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"100123"]; + self.codeID = @"FI"; + self.countryCode = [NSNumber numberWithInteger:358]; + self.internationalPrefix = @"00|99[049]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"(?:[1-3]00|[6-8]0)"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"116"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(116\\d{3})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[14]|2[09]|50|7[135]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4,10})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[25689][1-8]|3"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4,11})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCW +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[169]\\d{6,7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:[48]\\d{2}|50\\d|7(?:2[0-24]|[34]\\d|6[35-7]|77|8[7-9]))\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"94151234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:5(?:[12467]\\d|3[01])|6(?:[15-9]\\d|3[01]))\\d{4}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"95181234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60[0-2]\\d{4}" withPossibleNumberPattern:@"\\d{7}" withExample:@"6001234"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"955\\d{5}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"95581234"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CW"; + self.countryCode = [NSNumber numberWithInteger:599]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[13-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[34578]\\d{8}" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3(?:[256]\\d|4[124-9]|7[0-4])|4(?:1\\d|2[2-7]|3[1-79]|4[2-8]|7[239]|9[1-7]))\\d{6}" withPossibleNumberPattern:@"\\d{6,9}" withExample:@"322123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:14|5[01578]|68|7[0147-9]|9[0-35-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"555123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"706\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"706123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"706\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"706123456"]; + self.codeID = @"GE"; + self.countryCode = [NSNumber numberWithInteger:995]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[348]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"7"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"5"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFJ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[36-9]\\d{6}|0\\d{10}" withPossibleNumberPattern:@"\\d{7}(?:\\d{4})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[0-5]|6[25-7]|8[58])\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:7[0-8]|8[034679]|9\\d)\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0800\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:@"08001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FJ"; + self.countryCode = [NSNumber numberWithInteger:679]; + self.internationalPrefix = @"0(?:0|52)"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[36-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataCX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1458]\\d{5,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89164\\d{4}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"891641234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"14(?:5\\d|71)\\d{5}|4(?:[0-2]\\d|3[0-57-9]|4[47-9]|5[0-25-9]|6[6-9]|7[02-9]|8[147-9]|9[017-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"412345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"180(?:0\\d{3}|2)\\d{3}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"190[0126]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"13(?:00\\d{2})?\\d{4}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1300123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"500\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"500123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"550\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"550123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CX"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = @"(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]"; + self.preferredInternationalPrefix = @"0011"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGF +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"594(?:10|2[012457-9]|3[0-57-9]|4[3-9]|5[7-9]|6[0-3]|9[014])\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"594101234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"694(?:[04][0-7]|1[0-5]|3[018]|[29]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"694201234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GF"; + self.countryCode = [NSNumber numberWithInteger:594]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-7]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-47]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:@"31234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{4}" withPossibleNumberPattern:@"\\d{5}" withExample:@"51234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FK"; + self.countryCode = [NSNumber numberWithInteger:500]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[257-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2[2-6]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[4-79]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"96123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80001234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[09]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"90012345"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80112345"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"70012345"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:50|77)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"77123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CY"; + self.countryCode = [NSNumber numberWithInteger:357]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[135789]\\d{6,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1481\\d{6}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1481456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:781|839|911)\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7781123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:0(?:1111|\\d{6,7})|8\\d{7})|500\\d{6}" withPossibleNumberPattern:@"\\d{7}(?:\\d{2,3})?" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:87[123]|9(?:[01]\\d|8[0-3]))\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9012345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:4(?:5464\\d|[2-5]\\d{7})|70\\d{7})" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"8431234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"56\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5612345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"76(?:0[012]|2[356]|4[0134]|5[49]|6[0-369]|77|81|9[39])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7640123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:3[0347]|55)\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GG"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" x"; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataCZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-8]\\d{8}|9\\d{8,11}" withPossibleNumberPattern:@"\\d{9,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d{8}|(?:3[1257-9]|4[16-9]|5[13-9])\\d{7}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"212345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:60[1-8]|7(?:0[2-5]|[2379]\\d))\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"601123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:0[05689]|76)\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[134]\\d{7}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"811234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70[01]\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"700123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[17]0\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"910123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:5\\d|7[234])\\d{6}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"972123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:3\\d{9}|6\\d{7,10})" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"93123456789"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CZ"; + self.countryCode = [NSNumber numberWithInteger:420]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-8]|9[015-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-9]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"96"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(96\\d)(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9[36]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d)(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGH +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235]\\d{8}|8\\d{7}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:0[237]\\d|[167](?:2[0-6]|7\\d)|2(?:2[0-5]|7\\d)|3(?:2[0-3]|7\\d)|4(?:2[013-9]|3[01]|7\\d)|5(?:2[0-7]|7\\d)|8(?:2[0-2]|7\\d)|9(?:20|7\\d))\\d{5}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"302345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2[034678]\\d|5(?:[047]\\d|5[3-6]|6[01]))\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"231234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80012345"]; + self.codeID = @"GH"; + self.countryCode = [NSNumber numberWithInteger:233]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[235]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[39]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[2357]0[1-9]\\d{3}|9[2-6]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[2357]0[1-9]\\d{3}|9[2-7]\\d{5}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3501234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FM"; + self.countryCode = [NSNumber numberWithInteger:691]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataER +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[178]\\d{6}" withPossibleNumberPattern:@"\\d{6,7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:1[12568]|20|40|55|6[146])\\d{4}|8\\d{6}" withPossibleNumberPattern:@"\\d{6,7}" withExample:@"8370362"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"17[1-3]\\d{4}|7\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:@"7123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ER"; + self.countryCode = [NSNumber numberWithInteger:291]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGI +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2568]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:00\\d|1(?:6[24-7]|9\\d)|2(?:00|2[2457]))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"20012345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[46-8]|62)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"57123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"80123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[1-689]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"88123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"87\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"87123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GI"; + self.countryCode = [NSNumber numberWithInteger:350]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataES +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:[13]0|[28][0-8]|[47][1-9]|5[01346-9]|6[0457-9])\\d{6}|9(?:[1238][0-8]\\d{6}|4[1-9]\\d{6}|5\\d{7}|6(?:[0-8]\\d{6}|9(?:0(?:[0-57-9]\\d{4}|6(?:0[0-8]|1[1-9]|[2-9]\\d)\\d{2})|[1-9]\\d{5}))|7(?:[124-9]\\d{2}|3(?:[0-8]\\d|9[1-9]))\\d{4})" withPossibleNumberPattern:@"\\d{9}" withExample:@"810123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6\\d{6}|7[1-4]\\d{5}|9(?:6906(?:09|10)|7390\\d{2}))\\d{2}" withPossibleNumberPattern:@"\\d{9}" withExample:@"612345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[89]00\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[367]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"803123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[12]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"901123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"701234567"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"51\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"511234567"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ES"; + self.countryCode = [NSNumber numberWithInteger:34]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[89]00"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([89]00)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[568]|[79][0-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([5-9]\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:20|[3-4]\\d|8[19])\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[27][1-9]|5\\d)\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"211234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[257-9]\\d{3}" withPossibleNumberPattern:@"\\d{6}" withExample:@"802123"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90(?:[1345][15-7]|2[125-7]|99)\\d{2}" withPossibleNumberPattern:@"\\d{6}" withExample:@"901123"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:6[0-36]|88)\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"601234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FO"; + self.countryCode = [NSNumber numberWithInteger:298]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"(10(?:01|[12]0|88))"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{6})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataET +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-59]\\d{8}" withPossibleNumberPattern:@"\\d{7,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:11(?:1(?:1[124]|2[2-57]|3[1-5]|5[5-8]|8[6-8])|2(?:13|3[6-8]|5[89]|7[05-9]|8[2-6])|3(?:2[01]|3[0-289]|4[1289]|7[1-4]|87)|4(?:1[69]|3[2-49]|4[0-3]|6[5-8])|5(?:1[578]|44|5[0-4])|6(?:18|2[69]|4[5-7]|5[1-5]|6[0-59]|8[015-8]))|2(?:2(?:11[1-9]|22[0-7]|33\\d|44[1467]|66[1-68])|5(?:11[124-6]|33[2-8]|44[1467]|55[14]|66[1-3679]|77[124-79]|880))|3(?:3(?:11[0-46-8]|22[0-6]|33[0134689]|44[04]|55[0-6]|66[01467])|4(?:44[0-8]|55[0-69]|66[0-3]|77[1-5]))|4(?:6(?:22[0-24-7]|33[1-5]|44[13-69]|55[14-689]|660|88[1-4])|7(?:11[1-9]|22[1-9]|33[13-7]|44[13-6]|55[1-689]))|5(?:7(?:227|55[05]|(?:66|77)[14-8])|8(?:11[149]|22[013-79]|33[0-68]|44[013-8]|550|66[1-5]|77\\d)))\\d{4}" withPossibleNumberPattern:@"\\d{7,9}" withExample:@"111112345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9(?:[1-46]\\d|5[89])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"911234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"ET"; + self.countryCode = [NSNumber numberWithInteger:251]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-59]\\d)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-689]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:19|3[1-6]|6[14689]|8[14-79]|9\\d)\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"321000"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[245][2-9]\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"221234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"801234"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3[89]\\d{4}" withPossibleNumberPattern:@"\\d{6}" withExample:@"381234"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GL"; + self.countryCode = [NSNumber numberWithInteger:299]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataDZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[1-4]|[5-9]\\d)\\d{7}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:1\\d|2[013-79]|3[0-8]|4[0135689])\\d{6}|9619\\d{5}" withPossibleNumberPattern:@"\\d{8,9}" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[4-6]|7[7-9])\\d{7}|6(?:[569]\\d|7[0-6])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"551234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[3-689]1\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"808123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[12]1\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"98[23]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"983123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DZ"; + self.countryCode = [NSNumber numberWithInteger:213]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-4]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-4]\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[5-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([5-8]\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"9"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9\\d)(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGM +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:4(?:[23]\\d{2}|4(?:1[024679]|[6-9]\\d))|5(?:54[0-7]|6(?:[67]\\d)|7(?:1[04]|2[035]|3[58]|48))|8\\d{3})\\d{3}" withPossibleNumberPattern:@"\\d{7}" withExample:@"5661234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23679]\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:@"3012345"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GM"; + self.countryCode = [NSNumber numberWithInteger:220]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataID +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[1-79]\\d{6,10}|8\\d{7,11})" withPossibleNumberPattern:@"\\d{5,12}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:1(?:14\\d{3}|[0-8]\\d{6,7}|500\\d{3}|9\\d{6})|2\\d{6,8}|4\\d{7,8})|(?:2(?:[35][1-4]|6[0-8]|7[1-6]|8\\d|9[1-8])|3(?:1|[25][1-8]|3[1-68]|4[1-3]|6[1-3568]|7[0-469]|8\\d)|4(?:0[1-589]|1[01347-9]|2[0-36-8]|3[0-24-68]|43|5[1-378]|6[1-5]|7[134]|8[1245])|5(?:1[1-35-9]|2[25-8]|3[124-9]|4[1-3589]|5[1-46]|6[1-8])|6(?:19?|[25]\\d|3[1-69]|4[1-6])|7(?:02|[125][1-9]|[36]\\d|4[1-8]|7[0-36-9])|9(?:0[12]|1[013-8]|2[0-479]|5[125-8]|6[23679]|7[159]|8[01346]))\\d{5,8}" withPossibleNumberPattern:@"\\d{5,11}" withExample:@"612345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2(?:1(?:3[145]|4[01]|5[1-469]|60|8[0359]|9\\d)|2(?:88|9[1256])|3[1-4]9|4(?:36|91)|5(?:1[349]|[2-4]9)|6[0-7]9|7(?:[1-36]9|4[39])|8[1-5]9|9[1-48]9)|3(?:19[1-3]|2[12]9|3[13]9|4(?:1[69]|39)|5[14]9|6(?:1[69]|2[89])|709)|4[13]19|5(?:1(?:19|8[39])|4[129]9|6[12]9)|6(?:19[12]|2(?:[23]9|77))|7(?:1[13]9|2[15]9|419|5(?:1[89]|29)|6[15]9|7[178]9))\\d{5,6}|8[1-35-9]\\d{7,10}" withPossibleNumberPattern:@"\\d{9,12}" withExample:@"812345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"177\\d{6,8}|800\\d{5,7}" withPossibleNumberPattern:@"\\d{8,11}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"809\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8091234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"804\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8041234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1500\\d{3}|8071\\d{6}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"8071123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8071\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8071123456"]; + self.codeID = @"ID"; + self.countryCode = [NSNumber numberWithInteger:62]; + self.internationalPrefix = @"0(?:0[1789]|10(?:00|1[67]))"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2[124]|[36]1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[4579]|2[035-9]|[36][02-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"8[1-35-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{2})(\\d{3,4})(\\d{3,5})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"15"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)(500)(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"17"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(177)(\\d{6,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{5,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"804"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(804)(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"80[79]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(80\\d)(\\d)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataFR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-5]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6\\d{8}|7(?:00\\d{6}|[3-9]\\d{7})" withPossibleNumberPattern:@"\\d{9}" withExample:@"612345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[0-5]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89[1-37-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"891123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:1[019]|2[0156]|84|90)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"810123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:@"912345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80[6-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"806123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FR"; + self.countryCode = [NSNumber numberWithInteger:33]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-79]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-79])(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"11"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(1\\d{2})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[1-79]"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([1-79])(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4 $5" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"8"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(8\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"0 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[367]\\d{7,8}" withPossibleNumberPattern:@"\\d{8,9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30(?:24|3[12]|4[1-35-7]|5[13]|6[189]|[78]1|9[1478])\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"30241234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6[02356]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"601123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"722\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"722123456"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GN"; + self.countryCode = [NSNumber numberWithInteger:224]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[67]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[124-9]\\d{6,9}" withPossibleNumberPattern:@"\\d{5,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{7,8}|2(?:1\\d{6,7}|3\\d{7}|[24-9]\\d{5})|4(?:0[24]\\d{5}|[1-469]\\d{7}|5\\d{6}|7\\d{5}|8[0-46-9]\\d{7})|5(?:0[45]\\d{5}|1\\d{6}|[23679]\\d{7}|8\\d{5})|6(?:1\\d{6}|[237-9]\\d{5}|[4-6]\\d{7})|7[14]\\d{7}|9(?:1\\d{6}|[04]\\d{7}|[35-9]\\d{5})" withPossibleNumberPattern:@"\\d{5,10}" withExample:@"2212345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:22\\d{6}|[35-9]\\d{7})" withPossibleNumberPattern:@"\\d{9}" withExample:@"850123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"15(?:1[2-8]|[2-8]0|9[089])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1520123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18[59]0\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1850123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"700\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"700123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"76\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"761234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"818\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"818123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[35-9]\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8501234567"]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18[59]0\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1850123456"]; + self.codeID = @"IE"; + self.countryCode = [NSNumber numberWithInteger:353]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[24-9]|47|58|6[237-9]|9[35-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"40[24]|50[45]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"48"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(48)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"81"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(818)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"[24-69]|7[14]"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"76|8[35-9]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"([78]\\d)(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"70"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(700)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"1(?:8[059]|5)"]; + [numberFormats8_patternArray addObject:@"1(?:8[059]0|5)"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataHK +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[235-7]\\d{7}|8\\d{7,8}|9\\d{4,10}" withPossibleNumberPattern:@"\\d{5,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[23]\\d|58)\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[1-79]\\d|6\\d{2}|8[4-79]\\d|9(?:0[1-9]|[1-8]\\d))\\d{5}" withPossibleNumberPattern:@"\\d{8}" withExample:@"51234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900(?:[0-24-9]\\d{7}|3\\d{1,4})" withPossibleNumberPattern:@"\\d{5,11}" withExample:@"90012345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8[1-3]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"81123456"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"71234567"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"HK"; + self.countryCode = [NSNumber numberWithInteger:852]; + self.internationalPrefix = @"00(?:[126-9]|30|5[09])?"; + self.preferredInternationalPrefix = @"00"; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[235-7]|[89](?:0[1-9]|[1-9])"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(800)(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"900"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(900)(\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"900"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(900)(\\d{2,5})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[56]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"590(?:0[13468]|1[012]|2[0-68]|3[28]|4[0-8]|5[579]|6[0189]|70|8[0-689]|9\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"590201234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"690(?:0[0-7]|[1-9]\\d)\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"690301234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GP"; + self.countryCode = [NSNumber numberWithInteger:590]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([56]90)(\\d{2})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGQ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23589]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:3(?:3\\d[7-9]|[0-24-9]\\d[46])|5\\d{2}[7-9])\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"333091234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:222|55[15])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"222123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90\\d[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"900123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GQ"; + self.countryCode = [NSNumber numberWithInteger:240]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[235]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[26-9]\\d{9}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:1\\d{2}|2(?:2[1-46-9]|3[1-8]|4[1-7]|5[1-4]|6[1-8]|7[1-5]|[89][1-9])|3(?:1\\d|2[1-57]|[35][1-3]|4[13]|7[1-7]|8[124-6]|9[1-79])|4(?:1\\d|2[1-8]|3[1-4]|4[13-5]|6[1-578]|9[1-5])|5(?:1\\d|[29][1-4]|3[1-5]|4[124]|5[1-6])|6(?:1\\d|3[1245]|4[1-7]|5[13-9]|[269][1-6]|7[14]|8[1-5])|7(?:1\\d|2[1-5]|3[1-6]|4[1-7]|5[1-57]|6[135]|9[125-7])|8(?:1\\d|2[1-5]|[34][1-4]|9[1-57]))\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"2123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"69\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"6912345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8001234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"90[19]\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9091234567"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:0[16]|12|25)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8011234567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GR"; + self.countryCode = [NSNumber numberWithInteger:30]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"21|7"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([27]\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[2-9]1|[689]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"2[2-9][02-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(2\\d{3})(\\d{6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataHN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[237-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:2(?:0[019]|1[1-36]|[23]\\d|4[056]|5[57]|7[01389]|8[0146-9]|9[012])|4(?:07|2[3-59]|3[13-689]|4[0-68]|5[1-35])|5(?:16|4[3-5]|5\\d|6[4-6]|74)|6(?:[056]\\d|17|3[04]|4[0-378]|[78][0-8]|9[01])|7(?:6[46-9]|7[02-9]|8[034])|8(?:79|8[0-35789]|9[1-57-9]))\\d{4}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[37-9]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"91234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"HN"; + self.countryCode = [NSNumber numberWithInteger:504]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataJE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[135789]\\d{6,9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1534\\d{6}" withPossibleNumberPattern:@"\\d{6,10}" withExample:@"1534456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:509|7(?:00|97)|829|937)\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7797123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:07(?:35|81)|8901)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8007354567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:871206|90(?:066[59]|1810|71(?:07|55)))\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9018105678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:4(?:4(?:4(?:05|42|69)|703)|5(?:041|800))|70002)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8447034567"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"701511\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7015115678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"56\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5612345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"76(?:0[012]|2[356]|4[0134]|5[49]|6[0-369]|77|81|9[39])\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7640123456"]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3(?:0(?:07(?:35|81)|8901)|3\\d{4}|4(?:4(?:4(?:05|42|69)|703)|5(?:041|800))|7(?:0002|1206))\\d{4}|55\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5512345678"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"JE"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = @" x"; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-7]\\d{7}|1[89]\\d{9}" withPossibleNumberPattern:@"\\d{8}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[267][2-9]\\d{6}" withPossibleNumberPattern:@"\\d{8}" withExample:@"22456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[345]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:@"51234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"18[01]\\d{8}" withPossibleNumberPattern:@"\\d{11}" withExample:@"18001112222"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"19\\d{9}" withPossibleNumberPattern:@"\\d{11}" withExample:@"19001112222"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GT"; + self.countryCode = [NSNumber numberWithInteger:502]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-7]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataGU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[5689]\\d{9}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"671(?:3(?:00|3[39]|4[349]|55|6[26])|4(?:56|7[1-9]|8[236-9])|5(?:55|6[2-5]|88)|6(?:3[2-578]|4[24-9]|5[34]|78|8[5-9])|7(?:[079]7|2[0167]|3[45]|47|8[789])|8(?:[2-5789]8|6[48])|9(?:2[29]|6[79]|7[179]|8[789]|9[78]))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6713001234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"671(?:3(?:00|3[39]|4[349]|55|6[26])|4(?:56|7[1-9]|8[236-9])|5(?:55|6[2-5]|88)|6(?:3[2-578]|4[24-9]|5[34]|78|8[5-9])|7(?:[079]7|2[0167]|3[45]|47|8[789])|8(?:[2-5789]8|6[48])|9(?:2[29]|6[79]|7[179]|8[789]|9[78]))\\d{4}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"6713001234"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|44|55|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"8002123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"9002123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:00|33|44|66|77|88)[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5002345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GU"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"671"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataIL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[17]\\d{6,9}|[2-589]\\d{3}(?:\\d{3,6})?|6\\d{3}" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-489]\\d{7}" withPossibleNumberPattern:@"\\d{7,8}" withExample:@"21234567"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"5(?:[02-47-9]\\d{2}|5(?:01|2[23]|3[2-4]|4[45]|5[5689]|6[67]|7[0178]|8[6-9]|9[4-9])|6[2-9]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"501234567"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:80[019]\\d{3}|255)\\d{3}" withPossibleNumberPattern:@"\\d{7,10}" withExample:@"1800123456"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(?:212|(?:9(?:0[01]|19)|200)\\d{2})\\d{4}" withPossibleNumberPattern:@"\\d{8,10}" withExample:@"1919123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1700\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1700123456"]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7(?:18\\d|2[23]\\d|3[237]\\d|47\\d|6(?:5\\d|8[0168])|7\\d{2}|8(?:2\\d|33|55|77|81)|9[29]\\d)\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"771234567"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-689]\\d{3}|1599\\d{6}" withPossibleNumberPattern:@"\\d{4}(?:\\d{6})?" withExample:@"1599123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1700\\d{6}|[2-689]\\d{3}" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"1700123456"]; + self.codeID = @"IL"; + self.countryCode = [NSNumber numberWithInteger:972]; + self.internationalPrefix = @"0(?:0|1[2-9])"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[2-489]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([2-489])(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[57]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"([57]\\d)(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"1[7-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(1)([7-9]\\d{2})(\\d{3})(\\d{3})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"125"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1255)(\\d{3})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"120"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(1200)(\\d{3})(\\d{3})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"121"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(1212)(\\d{2})(\\d{2})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"15"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(1599)(\\d{6})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"[2-689]"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})" withFormat:@"*$1" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.h new file mode 100644 index 0000000000..ced01d51a0 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.h @@ -0,0 +1,10 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import + +@interface NBMetadataCoreMapper : NSObject + ++ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key; + +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.m new file mode 100644 index 0000000000..8052fb4619 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreMapper.m @@ -0,0 +1,914 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import "NBMetadataCoreMapper.h" + +@implementation NBMetadataCoreMapper + +static NSMutableDictionary *kMapCCode2CN; + ++ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + kMapCCode2CN = [[NSMutableDictionary alloc] init]; + + NSMutableArray *countryCode356Array = [[NSMutableArray alloc] init]; + [countryCode356Array addObject:@"MT"]; + [kMapCCode2CN setObject:countryCode356Array forKey:@"356"]; + + NSMutableArray *countryCode53Array = [[NSMutableArray alloc] init]; + [countryCode53Array addObject:@"CU"]; + [kMapCCode2CN setObject:countryCode53Array forKey:@"53"]; + + NSMutableArray *countryCode381Array = [[NSMutableArray alloc] init]; + [countryCode381Array addObject:@"RS"]; + [kMapCCode2CN setObject:countryCode381Array forKey:@"381"]; + + NSMutableArray *countryCode373Array = [[NSMutableArray alloc] init]; + [countryCode373Array addObject:@"MD"]; + [kMapCCode2CN setObject:countryCode373Array forKey:@"373"]; + + NSMutableArray *countryCode508Array = [[NSMutableArray alloc] init]; + [countryCode508Array addObject:@"PM"]; + [kMapCCode2CN setObject:countryCode508Array forKey:@"508"]; + + NSMutableArray *countryCode509Array = [[NSMutableArray alloc] init]; + [countryCode509Array addObject:@"HT"]; + [kMapCCode2CN setObject:countryCode509Array forKey:@"509"]; + + NSMutableArray *countryCode54Array = [[NSMutableArray alloc] init]; + [countryCode54Array addObject:@"AR"]; + [kMapCCode2CN setObject:countryCode54Array forKey:@"54"]; + + NSMutableArray *countryCode800Array = [[NSMutableArray alloc] init]; + [countryCode800Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode800Array forKey:@"800"]; + + NSMutableArray *countryCode268Array = [[NSMutableArray alloc] init]; + [countryCode268Array addObject:@"SZ"]; + [kMapCCode2CN setObject:countryCode268Array forKey:@"268"]; + + NSMutableArray *countryCode357Array = [[NSMutableArray alloc] init]; + [countryCode357Array addObject:@"CY"]; + [kMapCCode2CN setObject:countryCode357Array forKey:@"357"]; + + NSMutableArray *countryCode382Array = [[NSMutableArray alloc] init]; + [countryCode382Array addObject:@"ME"]; + [kMapCCode2CN setObject:countryCode382Array forKey:@"382"]; + + NSMutableArray *countryCode55Array = [[NSMutableArray alloc] init]; + [countryCode55Array addObject:@"BR"]; + [kMapCCode2CN setObject:countryCode55Array forKey:@"55"]; + + NSMutableArray *countryCode374Array = [[NSMutableArray alloc] init]; + [countryCode374Array addObject:@"AM"]; + [kMapCCode2CN setObject:countryCode374Array forKey:@"374"]; + + NSMutableArray *countryCode56Array = [[NSMutableArray alloc] init]; + [countryCode56Array addObject:@"CL"]; + [kMapCCode2CN setObject:countryCode56Array forKey:@"56"]; + + NSMutableArray *countryCode81Array = [[NSMutableArray alloc] init]; + [countryCode81Array addObject:@"JP"]; + [kMapCCode2CN setObject:countryCode81Array forKey:@"81"]; + + NSMutableArray *countryCode269Array = [[NSMutableArray alloc] init]; + [countryCode269Array addObject:@"KM"]; + [kMapCCode2CN setObject:countryCode269Array forKey:@"269"]; + + NSMutableArray *countryCode358Array = [[NSMutableArray alloc] init]; + [countryCode358Array addObject:@"FI"]; + [countryCode358Array addObject:@"AX"]; + [kMapCCode2CN setObject:countryCode358Array forKey:@"358"]; + + NSMutableArray *countryCode57Array = [[NSMutableArray alloc] init]; + [countryCode57Array addObject:@"CO"]; + [kMapCCode2CN setObject:countryCode57Array forKey:@"57"]; + + NSMutableArray *countryCode82Array = [[NSMutableArray alloc] init]; + [countryCode82Array addObject:@"KR"]; + [kMapCCode2CN setObject:countryCode82Array forKey:@"82"]; + + NSMutableArray *countryCode375Array = [[NSMutableArray alloc] init]; + [countryCode375Array addObject:@"BY"]; + [kMapCCode2CN setObject:countryCode375Array forKey:@"375"]; + + NSMutableArray *countryCode58Array = [[NSMutableArray alloc] init]; + [countryCode58Array addObject:@"VE"]; + [kMapCCode2CN setObject:countryCode58Array forKey:@"58"]; + + NSMutableArray *countryCode359Array = [[NSMutableArray alloc] init]; + [countryCode359Array addObject:@"BG"]; + [kMapCCode2CN setObject:countryCode359Array forKey:@"359"]; + + NSMutableArray *countryCode376Array = [[NSMutableArray alloc] init]; + [countryCode376Array addObject:@"AD"]; + [kMapCCode2CN setObject:countryCode376Array forKey:@"376"]; + + NSMutableArray *countryCode84Array = [[NSMutableArray alloc] init]; + [countryCode84Array addObject:@"VN"]; + [kMapCCode2CN setObject:countryCode84Array forKey:@"84"]; + + NSMutableArray *countryCode385Array = [[NSMutableArray alloc] init]; + [countryCode385Array addObject:@"HR"]; + [kMapCCode2CN setObject:countryCode385Array forKey:@"385"]; + + NSMutableArray *countryCode377Array = [[NSMutableArray alloc] init]; + [countryCode377Array addObject:@"MC"]; + [kMapCCode2CN setObject:countryCode377Array forKey:@"377"]; + + NSMutableArray *countryCode86Array = [[NSMutableArray alloc] init]; + [countryCode86Array addObject:@"CN"]; + [kMapCCode2CN setObject:countryCode86Array forKey:@"86"]; + + NSMutableArray *countryCode297Array = [[NSMutableArray alloc] init]; + [countryCode297Array addObject:@"AW"]; + [kMapCCode2CN setObject:countryCode297Array forKey:@"297"]; + + NSMutableArray *countryCode386Array = [[NSMutableArray alloc] init]; + [countryCode386Array addObject:@"SI"]; + [kMapCCode2CN setObject:countryCode386Array forKey:@"386"]; + + NSMutableArray *countryCode378Array = [[NSMutableArray alloc] init]; + [countryCode378Array addObject:@"SM"]; + [kMapCCode2CN setObject:countryCode378Array forKey:@"378"]; + + NSMutableArray *countryCode670Array = [[NSMutableArray alloc] init]; + [countryCode670Array addObject:@"TL"]; + [kMapCCode2CN setObject:countryCode670Array forKey:@"670"]; + + NSMutableArray *countryCode298Array = [[NSMutableArray alloc] init]; + [countryCode298Array addObject:@"FO"]; + [kMapCCode2CN setObject:countryCode298Array forKey:@"298"]; + + NSMutableArray *countryCode387Array = [[NSMutableArray alloc] init]; + [countryCode387Array addObject:@"BA"]; + [kMapCCode2CN setObject:countryCode387Array forKey:@"387"]; + + NSMutableArray *countryCode590Array = [[NSMutableArray alloc] init]; + [countryCode590Array addObject:@"GP"]; + [countryCode590Array addObject:@"BL"]; + [countryCode590Array addObject:@"MF"]; + [kMapCCode2CN setObject:countryCode590Array forKey:@"590"]; + + NSMutableArray *countryCode299Array = [[NSMutableArray alloc] init]; + [countryCode299Array addObject:@"GL"]; + [kMapCCode2CN setObject:countryCode299Array forKey:@"299"]; + + NSMutableArray *countryCode591Array = [[NSMutableArray alloc] init]; + [countryCode591Array addObject:@"BO"]; + [kMapCCode2CN setObject:countryCode591Array forKey:@"591"]; + + NSMutableArray *countryCode680Array = [[NSMutableArray alloc] init]; + [countryCode680Array addObject:@"PW"]; + [kMapCCode2CN setObject:countryCode680Array forKey:@"680"]; + + NSMutableArray *countryCode808Array = [[NSMutableArray alloc] init]; + [countryCode808Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode808Array forKey:@"808"]; + + NSMutableArray *countryCode672Array = [[NSMutableArray alloc] init]; + [countryCode672Array addObject:@"NF"]; + [kMapCCode2CN setObject:countryCode672Array forKey:@"672"]; + + NSMutableArray *countryCode850Array = [[NSMutableArray alloc] init]; + [countryCode850Array addObject:@"KP"]; + [kMapCCode2CN setObject:countryCode850Array forKey:@"850"]; + + NSMutableArray *countryCode389Array = [[NSMutableArray alloc] init]; + [countryCode389Array addObject:@"MK"]; + [kMapCCode2CN setObject:countryCode389Array forKey:@"389"]; + + NSMutableArray *countryCode592Array = [[NSMutableArray alloc] init]; + [countryCode592Array addObject:@"GY"]; + [kMapCCode2CN setObject:countryCode592Array forKey:@"592"]; + + NSMutableArray *countryCode681Array = [[NSMutableArray alloc] init]; + [countryCode681Array addObject:@"WF"]; + [kMapCCode2CN setObject:countryCode681Array forKey:@"681"]; + + NSMutableArray *countryCode673Array = [[NSMutableArray alloc] init]; + [countryCode673Array addObject:@"BN"]; + [kMapCCode2CN setObject:countryCode673Array forKey:@"673"]; + + NSMutableArray *countryCode690Array = [[NSMutableArray alloc] init]; + [countryCode690Array addObject:@"TK"]; + [kMapCCode2CN setObject:countryCode690Array forKey:@"690"]; + + NSMutableArray *countryCode593Array = [[NSMutableArray alloc] init]; + [countryCode593Array addObject:@"EC"]; + [kMapCCode2CN setObject:countryCode593Array forKey:@"593"]; + + NSMutableArray *countryCode682Array = [[NSMutableArray alloc] init]; + [countryCode682Array addObject:@"CK"]; + [kMapCCode2CN setObject:countryCode682Array forKey:@"682"]; + + NSMutableArray *countryCode674Array = [[NSMutableArray alloc] init]; + [countryCode674Array addObject:@"NR"]; + [kMapCCode2CN setObject:countryCode674Array forKey:@"674"]; + + NSMutableArray *countryCode852Array = [[NSMutableArray alloc] init]; + [countryCode852Array addObject:@"HK"]; + [kMapCCode2CN setObject:countryCode852Array forKey:@"852"]; + + NSMutableArray *countryCode691Array = [[NSMutableArray alloc] init]; + [countryCode691Array addObject:@"FM"]; + [kMapCCode2CN setObject:countryCode691Array forKey:@"691"]; + + NSMutableArray *countryCode594Array = [[NSMutableArray alloc] init]; + [countryCode594Array addObject:@"GF"]; + [kMapCCode2CN setObject:countryCode594Array forKey:@"594"]; + + NSMutableArray *countryCode683Array = [[NSMutableArray alloc] init]; + [countryCode683Array addObject:@"NU"]; + [kMapCCode2CN setObject:countryCode683Array forKey:@"683"]; + + NSMutableArray *countryCode675Array = [[NSMutableArray alloc] init]; + [countryCode675Array addObject:@"PG"]; + [kMapCCode2CN setObject:countryCode675Array forKey:@"675"]; + + NSMutableArray *countryCode30Array = [[NSMutableArray alloc] init]; + [countryCode30Array addObject:@"GR"]; + [kMapCCode2CN setObject:countryCode30Array forKey:@"30"]; + + NSMutableArray *countryCode853Array = [[NSMutableArray alloc] init]; + [countryCode853Array addObject:@"MO"]; + [kMapCCode2CN setObject:countryCode853Array forKey:@"853"]; + + NSMutableArray *countryCode692Array = [[NSMutableArray alloc] init]; + [countryCode692Array addObject:@"MH"]; + [kMapCCode2CN setObject:countryCode692Array forKey:@"692"]; + + NSMutableArray *countryCode595Array = [[NSMutableArray alloc] init]; + [countryCode595Array addObject:@"PY"]; + [kMapCCode2CN setObject:countryCode595Array forKey:@"595"]; + + NSMutableArray *countryCode31Array = [[NSMutableArray alloc] init]; + [countryCode31Array addObject:@"NL"]; + [kMapCCode2CN setObject:countryCode31Array forKey:@"31"]; + + NSMutableArray *countryCode870Array = [[NSMutableArray alloc] init]; + [countryCode870Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode870Array forKey:@"870"]; + + NSMutableArray *countryCode676Array = [[NSMutableArray alloc] init]; + [countryCode676Array addObject:@"TO"]; + [kMapCCode2CN setObject:countryCode676Array forKey:@"676"]; + + NSMutableArray *countryCode32Array = [[NSMutableArray alloc] init]; + [countryCode32Array addObject:@"BE"]; + [kMapCCode2CN setObject:countryCode32Array forKey:@"32"]; + + NSMutableArray *countryCode596Array = [[NSMutableArray alloc] init]; + [countryCode596Array addObject:@"MQ"]; + [kMapCCode2CN setObject:countryCode596Array forKey:@"596"]; + + NSMutableArray *countryCode685Array = [[NSMutableArray alloc] init]; + [countryCode685Array addObject:@"WS"]; + [kMapCCode2CN setObject:countryCode685Array forKey:@"685"]; + + NSMutableArray *countryCode33Array = [[NSMutableArray alloc] init]; + [countryCode33Array addObject:@"FR"]; + [kMapCCode2CN setObject:countryCode33Array forKey:@"33"]; + + NSMutableArray *countryCode960Array = [[NSMutableArray alloc] init]; + [countryCode960Array addObject:@"MV"]; + [kMapCCode2CN setObject:countryCode960Array forKey:@"960"]; + + NSMutableArray *countryCode677Array = [[NSMutableArray alloc] init]; + [countryCode677Array addObject:@"SB"]; + [kMapCCode2CN setObject:countryCode677Array forKey:@"677"]; + + NSMutableArray *countryCode855Array = [[NSMutableArray alloc] init]; + [countryCode855Array addObject:@"KH"]; + [kMapCCode2CN setObject:countryCode855Array forKey:@"855"]; + + NSMutableArray *countryCode34Array = [[NSMutableArray alloc] init]; + [countryCode34Array addObject:@"ES"]; + [kMapCCode2CN setObject:countryCode34Array forKey:@"34"]; + + NSMutableArray *countryCode880Array = [[NSMutableArray alloc] init]; + [countryCode880Array addObject:@"BD"]; + [kMapCCode2CN setObject:countryCode880Array forKey:@"880"]; + + NSMutableArray *countryCode597Array = [[NSMutableArray alloc] init]; + [countryCode597Array addObject:@"SR"]; + [kMapCCode2CN setObject:countryCode597Array forKey:@"597"]; + + NSMutableArray *countryCode686Array = [[NSMutableArray alloc] init]; + [countryCode686Array addObject:@"KI"]; + [kMapCCode2CN setObject:countryCode686Array forKey:@"686"]; + + NSMutableArray *countryCode961Array = [[NSMutableArray alloc] init]; + [countryCode961Array addObject:@"LB"]; + [kMapCCode2CN setObject:countryCode961Array forKey:@"961"]; + + NSMutableArray *countryCode60Array = [[NSMutableArray alloc] init]; + [countryCode60Array addObject:@"MY"]; + [kMapCCode2CN setObject:countryCode60Array forKey:@"60"]; + + NSMutableArray *countryCode678Array = [[NSMutableArray alloc] init]; + [countryCode678Array addObject:@"VU"]; + [kMapCCode2CN setObject:countryCode678Array forKey:@"678"]; + + NSMutableArray *countryCode856Array = [[NSMutableArray alloc] init]; + [countryCode856Array addObject:@"LA"]; + [kMapCCode2CN setObject:countryCode856Array forKey:@"856"]; + + NSMutableArray *countryCode881Array = [[NSMutableArray alloc] init]; + [countryCode881Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode881Array forKey:@"881"]; + + NSMutableArray *countryCode36Array = [[NSMutableArray alloc] init]; + [countryCode36Array addObject:@"HU"]; + [kMapCCode2CN setObject:countryCode36Array forKey:@"36"]; + + NSMutableArray *countryCode61Array = [[NSMutableArray alloc] init]; + [countryCode61Array addObject:@"AU"]; + [countryCode61Array addObject:@"CC"]; + [countryCode61Array addObject:@"CX"]; + [kMapCCode2CN setObject:countryCode61Array forKey:@"61"]; + + NSMutableArray *countryCode598Array = [[NSMutableArray alloc] init]; + [countryCode598Array addObject:@"UY"]; + [kMapCCode2CN setObject:countryCode598Array forKey:@"598"]; + + NSMutableArray *countryCode687Array = [[NSMutableArray alloc] init]; + [countryCode687Array addObject:@"NC"]; + [kMapCCode2CN setObject:countryCode687Array forKey:@"687"]; + + NSMutableArray *countryCode962Array = [[NSMutableArray alloc] init]; + [countryCode962Array addObject:@"JO"]; + [kMapCCode2CN setObject:countryCode962Array forKey:@"962"]; + + NSMutableArray *countryCode62Array = [[NSMutableArray alloc] init]; + [countryCode62Array addObject:@"ID"]; + [kMapCCode2CN setObject:countryCode62Array forKey:@"62"]; + + NSMutableArray *countryCode679Array = [[NSMutableArray alloc] init]; + [countryCode679Array addObject:@"FJ"]; + [kMapCCode2CN setObject:countryCode679Array forKey:@"679"]; + + NSMutableArray *countryCode882Array = [[NSMutableArray alloc] init]; + [countryCode882Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode882Array forKey:@"882"]; + + NSMutableArray *countryCode970Array = [[NSMutableArray alloc] init]; + [countryCode970Array addObject:@"PS"]; + [kMapCCode2CN setObject:countryCode970Array forKey:@"970"]; + + NSMutableArray *countryCode971Array = [[NSMutableArray alloc] init]; + [countryCode971Array addObject:@"AE"]; + [kMapCCode2CN setObject:countryCode971Array forKey:@"971"]; + + NSMutableArray *countryCode63Array = [[NSMutableArray alloc] init]; + [countryCode63Array addObject:@"PH"]; + [kMapCCode2CN setObject:countryCode63Array forKey:@"63"]; + + NSMutableArray *countryCode599Array = [[NSMutableArray alloc] init]; + [countryCode599Array addObject:@"CW"]; + [countryCode599Array addObject:@"BQ"]; + [kMapCCode2CN setObject:countryCode599Array forKey:@"599"]; + + NSMutableArray *countryCode688Array = [[NSMutableArray alloc] init]; + [countryCode688Array addObject:@"TV"]; + [kMapCCode2CN setObject:countryCode688Array forKey:@"688"]; + + NSMutableArray *countryCode963Array = [[NSMutableArray alloc] init]; + [countryCode963Array addObject:@"SY"]; + [kMapCCode2CN setObject:countryCode963Array forKey:@"963"]; + + NSMutableArray *countryCode39Array = [[NSMutableArray alloc] init]; + [countryCode39Array addObject:@"IT"]; + [countryCode39Array addObject:@"VA"]; + [kMapCCode2CN setObject:countryCode39Array forKey:@"39"]; + + NSMutableArray *countryCode64Array = [[NSMutableArray alloc] init]; + [countryCode64Array addObject:@"NZ"]; + [kMapCCode2CN setObject:countryCode64Array forKey:@"64"]; + + NSMutableArray *countryCode883Array = [[NSMutableArray alloc] init]; + [countryCode883Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode883Array forKey:@"883"]; + + NSMutableArray *countryCode972Array = [[NSMutableArray alloc] init]; + [countryCode972Array addObject:@"IL"]; + [kMapCCode2CN setObject:countryCode972Array forKey:@"972"]; + + NSMutableArray *countryCode65Array = [[NSMutableArray alloc] init]; + [countryCode65Array addObject:@"SG"]; + [kMapCCode2CN setObject:countryCode65Array forKey:@"65"]; + + NSMutableArray *countryCode90Array = [[NSMutableArray alloc] init]; + [countryCode90Array addObject:@"TR"]; + [kMapCCode2CN setObject:countryCode90Array forKey:@"90"]; + + NSMutableArray *countryCode689Array = [[NSMutableArray alloc] init]; + [countryCode689Array addObject:@"PF"]; + [kMapCCode2CN setObject:countryCode689Array forKey:@"689"]; + + NSMutableArray *countryCode964Array = [[NSMutableArray alloc] init]; + [countryCode964Array addObject:@"IQ"]; + [kMapCCode2CN setObject:countryCode964Array forKey:@"964"]; + + NSMutableArray *countryCode1Array = [[NSMutableArray alloc] init]; + [countryCode1Array addObject:@"US"]; + [countryCode1Array addObject:@"AG"]; + [countryCode1Array addObject:@"AI"]; + [countryCode1Array addObject:@"AS"]; + [countryCode1Array addObject:@"BB"]; + [countryCode1Array addObject:@"BM"]; + [countryCode1Array addObject:@"BS"]; + [countryCode1Array addObject:@"CA"]; + [countryCode1Array addObject:@"DM"]; + [countryCode1Array addObject:@"DO"]; + [countryCode1Array addObject:@"GD"]; + [countryCode1Array addObject:@"GU"]; + [countryCode1Array addObject:@"JM"]; + [countryCode1Array addObject:@"KN"]; + [countryCode1Array addObject:@"KY"]; + [countryCode1Array addObject:@"LC"]; + [countryCode1Array addObject:@"MP"]; + [countryCode1Array addObject:@"MS"]; + [countryCode1Array addObject:@"PR"]; + [countryCode1Array addObject:@"SX"]; + [countryCode1Array addObject:@"TC"]; + [countryCode1Array addObject:@"TT"]; + [countryCode1Array addObject:@"VC"]; + [countryCode1Array addObject:@"VG"]; + [countryCode1Array addObject:@"VI"]; + [kMapCCode2CN setObject:countryCode1Array forKey:@"1"]; + + NSMutableArray *countryCode66Array = [[NSMutableArray alloc] init]; + [countryCode66Array addObject:@"TH"]; + [kMapCCode2CN setObject:countryCode66Array forKey:@"66"]; + + NSMutableArray *countryCode91Array = [[NSMutableArray alloc] init]; + [countryCode91Array addObject:@"IN"]; + [kMapCCode2CN setObject:countryCode91Array forKey:@"91"]; + + NSMutableArray *countryCode973Array = [[NSMutableArray alloc] init]; + [countryCode973Array addObject:@"BH"]; + [kMapCCode2CN setObject:countryCode973Array forKey:@"973"]; + + NSMutableArray *countryCode965Array = [[NSMutableArray alloc] init]; + [countryCode965Array addObject:@"KW"]; + [kMapCCode2CN setObject:countryCode965Array forKey:@"965"]; + + NSMutableArray *countryCode92Array = [[NSMutableArray alloc] init]; + [countryCode92Array addObject:@"PK"]; + [kMapCCode2CN setObject:countryCode92Array forKey:@"92"]; + + NSMutableArray *countryCode93Array = [[NSMutableArray alloc] init]; + [countryCode93Array addObject:@"AF"]; + [kMapCCode2CN setObject:countryCode93Array forKey:@"93"]; + + NSMutableArray *countryCode974Array = [[NSMutableArray alloc] init]; + [countryCode974Array addObject:@"QA"]; + [kMapCCode2CN setObject:countryCode974Array forKey:@"974"]; + + NSMutableArray *countryCode966Array = [[NSMutableArray alloc] init]; + [countryCode966Array addObject:@"SA"]; + [kMapCCode2CN setObject:countryCode966Array forKey:@"966"]; + + NSMutableArray *countryCode94Array = [[NSMutableArray alloc] init]; + [countryCode94Array addObject:@"LK"]; + [kMapCCode2CN setObject:countryCode94Array forKey:@"94"]; + + NSMutableArray *countryCode7Array = [[NSMutableArray alloc] init]; + [countryCode7Array addObject:@"RU"]; + [countryCode7Array addObject:@"KZ"]; + [kMapCCode2CN setObject:countryCode7Array forKey:@"7"]; + + NSMutableArray *countryCode886Array = [[NSMutableArray alloc] init]; + [countryCode886Array addObject:@"TW"]; + [kMapCCode2CN setObject:countryCode886Array forKey:@"886"]; + + NSMutableArray *countryCode95Array = [[NSMutableArray alloc] init]; + [countryCode95Array addObject:@"MM"]; + [kMapCCode2CN setObject:countryCode95Array forKey:@"95"]; + + NSMutableArray *countryCode878Array = [[NSMutableArray alloc] init]; + [countryCode878Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode878Array forKey:@"878"]; + + NSMutableArray *countryCode967Array = [[NSMutableArray alloc] init]; + [countryCode967Array addObject:@"YE"]; + [kMapCCode2CN setObject:countryCode967Array forKey:@"967"]; + + NSMutableArray *countryCode975Array = [[NSMutableArray alloc] init]; + [countryCode975Array addObject:@"BT"]; + [kMapCCode2CN setObject:countryCode975Array forKey:@"975"]; + + NSMutableArray *countryCode992Array = [[NSMutableArray alloc] init]; + [countryCode992Array addObject:@"TJ"]; + [kMapCCode2CN setObject:countryCode992Array forKey:@"992"]; + + NSMutableArray *countryCode976Array = [[NSMutableArray alloc] init]; + [countryCode976Array addObject:@"MN"]; + [kMapCCode2CN setObject:countryCode976Array forKey:@"976"]; + + NSMutableArray *countryCode968Array = [[NSMutableArray alloc] init]; + [countryCode968Array addObject:@"OM"]; + [kMapCCode2CN setObject:countryCode968Array forKey:@"968"]; + + NSMutableArray *countryCode993Array = [[NSMutableArray alloc] init]; + [countryCode993Array addObject:@"TM"]; + [kMapCCode2CN setObject:countryCode993Array forKey:@"993"]; + + NSMutableArray *countryCode98Array = [[NSMutableArray alloc] init]; + [countryCode98Array addObject:@"IR"]; + [kMapCCode2CN setObject:countryCode98Array forKey:@"98"]; + + NSMutableArray *countryCode888Array = [[NSMutableArray alloc] init]; + [countryCode888Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode888Array forKey:@"888"]; + + NSMutableArray *countryCode977Array = [[NSMutableArray alloc] init]; + [countryCode977Array addObject:@"NP"]; + [kMapCCode2CN setObject:countryCode977Array forKey:@"977"]; + + NSMutableArray *countryCode994Array = [[NSMutableArray alloc] init]; + [countryCode994Array addObject:@"AZ"]; + [kMapCCode2CN setObject:countryCode994Array forKey:@"994"]; + + NSMutableArray *countryCode995Array = [[NSMutableArray alloc] init]; + [countryCode995Array addObject:@"GE"]; + [kMapCCode2CN setObject:countryCode995Array forKey:@"995"]; + + NSMutableArray *countryCode979Array = [[NSMutableArray alloc] init]; + [countryCode979Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode979Array forKey:@"979"]; + + NSMutableArray *countryCode996Array = [[NSMutableArray alloc] init]; + [countryCode996Array addObject:@"KG"]; + [kMapCCode2CN setObject:countryCode996Array forKey:@"996"]; + + NSMutableArray *countryCode998Array = [[NSMutableArray alloc] init]; + [countryCode998Array addObject:@"UZ"]; + [kMapCCode2CN setObject:countryCode998Array forKey:@"998"]; + + NSMutableArray *countryCode40Array = [[NSMutableArray alloc] init]; + [countryCode40Array addObject:@"RO"]; + [kMapCCode2CN setObject:countryCode40Array forKey:@"40"]; + + NSMutableArray *countryCode41Array = [[NSMutableArray alloc] init]; + [countryCode41Array addObject:@"CH"]; + [kMapCCode2CN setObject:countryCode41Array forKey:@"41"]; + + NSMutableArray *countryCode43Array = [[NSMutableArray alloc] init]; + [countryCode43Array addObject:@"AT"]; + [kMapCCode2CN setObject:countryCode43Array forKey:@"43"]; + + NSMutableArray *countryCode44Array = [[NSMutableArray alloc] init]; + [countryCode44Array addObject:@"GB"]; + [countryCode44Array addObject:@"GG"]; + [countryCode44Array addObject:@"IM"]; + [countryCode44Array addObject:@"JE"]; + [kMapCCode2CN setObject:countryCode44Array forKey:@"44"]; + + NSMutableArray *countryCode211Array = [[NSMutableArray alloc] init]; + [countryCode211Array addObject:@"SS"]; + [kMapCCode2CN setObject:countryCode211Array forKey:@"211"]; + + NSMutableArray *countryCode45Array = [[NSMutableArray alloc] init]; + [countryCode45Array addObject:@"DK"]; + [kMapCCode2CN setObject:countryCode45Array forKey:@"45"]; + + NSMutableArray *countryCode220Array = [[NSMutableArray alloc] init]; + [countryCode220Array addObject:@"GM"]; + [kMapCCode2CN setObject:countryCode220Array forKey:@"220"]; + + NSMutableArray *countryCode212Array = [[NSMutableArray alloc] init]; + [countryCode212Array addObject:@"MA"]; + [countryCode212Array addObject:@"EH"]; + [kMapCCode2CN setObject:countryCode212Array forKey:@"212"]; + + NSMutableArray *countryCode46Array = [[NSMutableArray alloc] init]; + [countryCode46Array addObject:@"SE"]; + [kMapCCode2CN setObject:countryCode46Array forKey:@"46"]; + + NSMutableArray *countryCode47Array = [[NSMutableArray alloc] init]; + [countryCode47Array addObject:@"NO"]; + [countryCode47Array addObject:@"SJ"]; + [kMapCCode2CN setObject:countryCode47Array forKey:@"47"]; + + NSMutableArray *countryCode221Array = [[NSMutableArray alloc] init]; + [countryCode221Array addObject:@"SN"]; + [kMapCCode2CN setObject:countryCode221Array forKey:@"221"]; + + NSMutableArray *countryCode213Array = [[NSMutableArray alloc] init]; + [countryCode213Array addObject:@"DZ"]; + [kMapCCode2CN setObject:countryCode213Array forKey:@"213"]; + + NSMutableArray *countryCode48Array = [[NSMutableArray alloc] init]; + [countryCode48Array addObject:@"PL"]; + [kMapCCode2CN setObject:countryCode48Array forKey:@"48"]; + + NSMutableArray *countryCode230Array = [[NSMutableArray alloc] init]; + [countryCode230Array addObject:@"MU"]; + [kMapCCode2CN setObject:countryCode230Array forKey:@"230"]; + + NSMutableArray *countryCode222Array = [[NSMutableArray alloc] init]; + [countryCode222Array addObject:@"MR"]; + [kMapCCode2CN setObject:countryCode222Array forKey:@"222"]; + + NSMutableArray *countryCode49Array = [[NSMutableArray alloc] init]; + [countryCode49Array addObject:@"DE"]; + [kMapCCode2CN setObject:countryCode49Array forKey:@"49"]; + + NSMutableArray *countryCode231Array = [[NSMutableArray alloc] init]; + [countryCode231Array addObject:@"LR"]; + [kMapCCode2CN setObject:countryCode231Array forKey:@"231"]; + + NSMutableArray *countryCode223Array = [[NSMutableArray alloc] init]; + [countryCode223Array addObject:@"ML"]; + [kMapCCode2CN setObject:countryCode223Array forKey:@"223"]; + + NSMutableArray *countryCode240Array = [[NSMutableArray alloc] init]; + [countryCode240Array addObject:@"GQ"]; + [kMapCCode2CN setObject:countryCode240Array forKey:@"240"]; + + NSMutableArray *countryCode232Array = [[NSMutableArray alloc] init]; + [countryCode232Array addObject:@"SL"]; + [kMapCCode2CN setObject:countryCode232Array forKey:@"232"]; + + NSMutableArray *countryCode224Array = [[NSMutableArray alloc] init]; + [countryCode224Array addObject:@"GN"]; + [kMapCCode2CN setObject:countryCode224Array forKey:@"224"]; + + NSMutableArray *countryCode216Array = [[NSMutableArray alloc] init]; + [countryCode216Array addObject:@"TN"]; + [kMapCCode2CN setObject:countryCode216Array forKey:@"216"]; + + NSMutableArray *countryCode241Array = [[NSMutableArray alloc] init]; + [countryCode241Array addObject:@"GA"]; + [kMapCCode2CN setObject:countryCode241Array forKey:@"241"]; + + NSMutableArray *countryCode233Array = [[NSMutableArray alloc] init]; + [countryCode233Array addObject:@"GH"]; + [kMapCCode2CN setObject:countryCode233Array forKey:@"233"]; + + NSMutableArray *countryCode225Array = [[NSMutableArray alloc] init]; + [countryCode225Array addObject:@"CI"]; + [kMapCCode2CN setObject:countryCode225Array forKey:@"225"]; + + NSMutableArray *countryCode250Array = [[NSMutableArray alloc] init]; + [countryCode250Array addObject:@"RW"]; + [kMapCCode2CN setObject:countryCode250Array forKey:@"250"]; + + NSMutableArray *countryCode500Array = [[NSMutableArray alloc] init]; + [countryCode500Array addObject:@"FK"]; + [kMapCCode2CN setObject:countryCode500Array forKey:@"500"]; + + NSMutableArray *countryCode242Array = [[NSMutableArray alloc] init]; + [countryCode242Array addObject:@"CG"]; + [kMapCCode2CN setObject:countryCode242Array forKey:@"242"]; + + NSMutableArray *countryCode420Array = [[NSMutableArray alloc] init]; + [countryCode420Array addObject:@"CZ"]; + [kMapCCode2CN setObject:countryCode420Array forKey:@"420"]; + + NSMutableArray *countryCode234Array = [[NSMutableArray alloc] init]; + [countryCode234Array addObject:@"NG"]; + [kMapCCode2CN setObject:countryCode234Array forKey:@"234"]; + + NSMutableArray *countryCode226Array = [[NSMutableArray alloc] init]; + [countryCode226Array addObject:@"BF"]; + [kMapCCode2CN setObject:countryCode226Array forKey:@"226"]; + + NSMutableArray *countryCode251Array = [[NSMutableArray alloc] init]; + [countryCode251Array addObject:@"ET"]; + [kMapCCode2CN setObject:countryCode251Array forKey:@"251"]; + + NSMutableArray *countryCode501Array = [[NSMutableArray alloc] init]; + [countryCode501Array addObject:@"BZ"]; + [kMapCCode2CN setObject:countryCode501Array forKey:@"501"]; + + NSMutableArray *countryCode218Array = [[NSMutableArray alloc] init]; + [countryCode218Array addObject:@"LY"]; + [kMapCCode2CN setObject:countryCode218Array forKey:@"218"]; + + NSMutableArray *countryCode243Array = [[NSMutableArray alloc] init]; + [countryCode243Array addObject:@"CD"]; + [kMapCCode2CN setObject:countryCode243Array forKey:@"243"]; + + NSMutableArray *countryCode421Array = [[NSMutableArray alloc] init]; + [countryCode421Array addObject:@"SK"]; + [kMapCCode2CN setObject:countryCode421Array forKey:@"421"]; + + NSMutableArray *countryCode235Array = [[NSMutableArray alloc] init]; + [countryCode235Array addObject:@"TD"]; + [kMapCCode2CN setObject:countryCode235Array forKey:@"235"]; + + NSMutableArray *countryCode260Array = [[NSMutableArray alloc] init]; + [countryCode260Array addObject:@"ZM"]; + [kMapCCode2CN setObject:countryCode260Array forKey:@"260"]; + + NSMutableArray *countryCode227Array = [[NSMutableArray alloc] init]; + [countryCode227Array addObject:@"NE"]; + [kMapCCode2CN setObject:countryCode227Array forKey:@"227"]; + + NSMutableArray *countryCode252Array = [[NSMutableArray alloc] init]; + [countryCode252Array addObject:@"SO"]; + [kMapCCode2CN setObject:countryCode252Array forKey:@"252"]; + + NSMutableArray *countryCode502Array = [[NSMutableArray alloc] init]; + [countryCode502Array addObject:@"GT"]; + [kMapCCode2CN setObject:countryCode502Array forKey:@"502"]; + + NSMutableArray *countryCode244Array = [[NSMutableArray alloc] init]; + [countryCode244Array addObject:@"AO"]; + [kMapCCode2CN setObject:countryCode244Array forKey:@"244"]; + + NSMutableArray *countryCode236Array = [[NSMutableArray alloc] init]; + [countryCode236Array addObject:@"CF"]; + [kMapCCode2CN setObject:countryCode236Array forKey:@"236"]; + + NSMutableArray *countryCode261Array = [[NSMutableArray alloc] init]; + [countryCode261Array addObject:@"MG"]; + [kMapCCode2CN setObject:countryCode261Array forKey:@"261"]; + + NSMutableArray *countryCode350Array = [[NSMutableArray alloc] init]; + [countryCode350Array addObject:@"GI"]; + [kMapCCode2CN setObject:countryCode350Array forKey:@"350"]; + + NSMutableArray *countryCode228Array = [[NSMutableArray alloc] init]; + [countryCode228Array addObject:@"TG"]; + [kMapCCode2CN setObject:countryCode228Array forKey:@"228"]; + + NSMutableArray *countryCode253Array = [[NSMutableArray alloc] init]; + [countryCode253Array addObject:@"DJ"]; + [kMapCCode2CN setObject:countryCode253Array forKey:@"253"]; + + NSMutableArray *countryCode503Array = [[NSMutableArray alloc] init]; + [countryCode503Array addObject:@"SV"]; + [kMapCCode2CN setObject:countryCode503Array forKey:@"503"]; + + NSMutableArray *countryCode245Array = [[NSMutableArray alloc] init]; + [countryCode245Array addObject:@"GW"]; + [kMapCCode2CN setObject:countryCode245Array forKey:@"245"]; + + NSMutableArray *countryCode423Array = [[NSMutableArray alloc] init]; + [countryCode423Array addObject:@"LI"]; + [kMapCCode2CN setObject:countryCode423Array forKey:@"423"]; + + NSMutableArray *countryCode237Array = [[NSMutableArray alloc] init]; + [countryCode237Array addObject:@"CM"]; + [kMapCCode2CN setObject:countryCode237Array forKey:@"237"]; + + NSMutableArray *countryCode262Array = [[NSMutableArray alloc] init]; + [countryCode262Array addObject:@"RE"]; + [countryCode262Array addObject:@"YT"]; + [kMapCCode2CN setObject:countryCode262Array forKey:@"262"]; + + NSMutableArray *countryCode351Array = [[NSMutableArray alloc] init]; + [countryCode351Array addObject:@"PT"]; + [kMapCCode2CN setObject:countryCode351Array forKey:@"351"]; + + NSMutableArray *countryCode229Array = [[NSMutableArray alloc] init]; + [countryCode229Array addObject:@"BJ"]; + [kMapCCode2CN setObject:countryCode229Array forKey:@"229"]; + + NSMutableArray *countryCode254Array = [[NSMutableArray alloc] init]; + [countryCode254Array addObject:@"KE"]; + [kMapCCode2CN setObject:countryCode254Array forKey:@"254"]; + + NSMutableArray *countryCode504Array = [[NSMutableArray alloc] init]; + [countryCode504Array addObject:@"HN"]; + [kMapCCode2CN setObject:countryCode504Array forKey:@"504"]; + + NSMutableArray *countryCode246Array = [[NSMutableArray alloc] init]; + [countryCode246Array addObject:@"IO"]; + [kMapCCode2CN setObject:countryCode246Array forKey:@"246"]; + + NSMutableArray *countryCode20Array = [[NSMutableArray alloc] init]; + [countryCode20Array addObject:@"EG"]; + [kMapCCode2CN setObject:countryCode20Array forKey:@"20"]; + + NSMutableArray *countryCode238Array = [[NSMutableArray alloc] init]; + [countryCode238Array addObject:@"CV"]; + [kMapCCode2CN setObject:countryCode238Array forKey:@"238"]; + + NSMutableArray *countryCode263Array = [[NSMutableArray alloc] init]; + [countryCode263Array addObject:@"ZW"]; + [kMapCCode2CN setObject:countryCode263Array forKey:@"263"]; + + NSMutableArray *countryCode352Array = [[NSMutableArray alloc] init]; + [countryCode352Array addObject:@"LU"]; + [kMapCCode2CN setObject:countryCode352Array forKey:@"352"]; + + NSMutableArray *countryCode255Array = [[NSMutableArray alloc] init]; + [countryCode255Array addObject:@"TZ"]; + [kMapCCode2CN setObject:countryCode255Array forKey:@"255"]; + + NSMutableArray *countryCode505Array = [[NSMutableArray alloc] init]; + [countryCode505Array addObject:@"NI"]; + [kMapCCode2CN setObject:countryCode505Array forKey:@"505"]; + + NSMutableArray *countryCode247Array = [[NSMutableArray alloc] init]; + [countryCode247Array addObject:@"AC"]; + [kMapCCode2CN setObject:countryCode247Array forKey:@"247"]; + + NSMutableArray *countryCode239Array = [[NSMutableArray alloc] init]; + [countryCode239Array addObject:@"ST"]; + [kMapCCode2CN setObject:countryCode239Array forKey:@"239"]; + + NSMutableArray *countryCode264Array = [[NSMutableArray alloc] init]; + [countryCode264Array addObject:@"NA"]; + [kMapCCode2CN setObject:countryCode264Array forKey:@"264"]; + + NSMutableArray *countryCode353Array = [[NSMutableArray alloc] init]; + [countryCode353Array addObject:@"IE"]; + [kMapCCode2CN setObject:countryCode353Array forKey:@"353"]; + + NSMutableArray *countryCode256Array = [[NSMutableArray alloc] init]; + [countryCode256Array addObject:@"UG"]; + [kMapCCode2CN setObject:countryCode256Array forKey:@"256"]; + + NSMutableArray *countryCode370Array = [[NSMutableArray alloc] init]; + [countryCode370Array addObject:@"LT"]; + [kMapCCode2CN setObject:countryCode370Array forKey:@"370"]; + + NSMutableArray *countryCode506Array = [[NSMutableArray alloc] init]; + [countryCode506Array addObject:@"CR"]; + [kMapCCode2CN setObject:countryCode506Array forKey:@"506"]; + + NSMutableArray *countryCode248Array = [[NSMutableArray alloc] init]; + [countryCode248Array addObject:@"SC"]; + [kMapCCode2CN setObject:countryCode248Array forKey:@"248"]; + + NSMutableArray *countryCode265Array = [[NSMutableArray alloc] init]; + [countryCode265Array addObject:@"MW"]; + [kMapCCode2CN setObject:countryCode265Array forKey:@"265"]; + + NSMutableArray *countryCode290Array = [[NSMutableArray alloc] init]; + [countryCode290Array addObject:@"SH"]; + [countryCode290Array addObject:@"TA"]; + [kMapCCode2CN setObject:countryCode290Array forKey:@"290"]; + + NSMutableArray *countryCode354Array = [[NSMutableArray alloc] init]; + [countryCode354Array addObject:@"IS"]; + [kMapCCode2CN setObject:countryCode354Array forKey:@"354"]; + + NSMutableArray *countryCode257Array = [[NSMutableArray alloc] init]; + [countryCode257Array addObject:@"BI"]; + [kMapCCode2CN setObject:countryCode257Array forKey:@"257"]; + + NSMutableArray *countryCode371Array = [[NSMutableArray alloc] init]; + [countryCode371Array addObject:@"LV"]; + [kMapCCode2CN setObject:countryCode371Array forKey:@"371"]; + + NSMutableArray *countryCode507Array = [[NSMutableArray alloc] init]; + [countryCode507Array addObject:@"PA"]; + [kMapCCode2CN setObject:countryCode507Array forKey:@"507"]; + + NSMutableArray *countryCode249Array = [[NSMutableArray alloc] init]; + [countryCode249Array addObject:@"SD"]; + [kMapCCode2CN setObject:countryCode249Array forKey:@"249"]; + + NSMutableArray *countryCode266Array = [[NSMutableArray alloc] init]; + [countryCode266Array addObject:@"LS"]; + [kMapCCode2CN setObject:countryCode266Array forKey:@"266"]; + + NSMutableArray *countryCode51Array = [[NSMutableArray alloc] init]; + [countryCode51Array addObject:@"PE"]; + [kMapCCode2CN setObject:countryCode51Array forKey:@"51"]; + + NSMutableArray *countryCode291Array = [[NSMutableArray alloc] init]; + [countryCode291Array addObject:@"ER"]; + [kMapCCode2CN setObject:countryCode291Array forKey:@"291"]; + + NSMutableArray *countryCode258Array = [[NSMutableArray alloc] init]; + [countryCode258Array addObject:@"MZ"]; + [kMapCCode2CN setObject:countryCode258Array forKey:@"258"]; + + NSMutableArray *countryCode355Array = [[NSMutableArray alloc] init]; + [countryCode355Array addObject:@"AL"]; + [kMapCCode2CN setObject:countryCode355Array forKey:@"355"]; + + NSMutableArray *countryCode372Array = [[NSMutableArray alloc] init]; + [countryCode372Array addObject:@"EE"]; + [kMapCCode2CN setObject:countryCode372Array forKey:@"372"]; + + NSMutableArray *countryCode27Array = [[NSMutableArray alloc] init]; + [countryCode27Array addObject:@"ZA"]; + [kMapCCode2CN setObject:countryCode27Array forKey:@"27"]; + + NSMutableArray *countryCode52Array = [[NSMutableArray alloc] init]; + [countryCode52Array addObject:@"MX"]; + [kMapCCode2CN setObject:countryCode52Array forKey:@"52"]; + + NSMutableArray *countryCode380Array = [[NSMutableArray alloc] init]; + [countryCode380Array addObject:@"UA"]; + [kMapCCode2CN setObject:countryCode380Array forKey:@"380"]; + + NSMutableArray *countryCode267Array = [[NSMutableArray alloc] init]; + [countryCode267Array addObject:@"BW"]; + [kMapCCode2CN setObject:countryCode267Array forKey:@"267"]; + }); + return [kMapCCode2CN objectForKey:key]; +} + +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.h new file mode 100644 index 0000000000..4170c16905 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.h @@ -0,0 +1,98 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import +#import "NBPhoneMetaData.h" + +@interface NBPhoneMetadataTestAD : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestBR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestAU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestBB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestAE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestCX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestBS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestDE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestKR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestNZ : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestPL : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestSE : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestCA : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestAO : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTest800 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestYT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestFR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestGG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestHU : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestSG : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestJP : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestCC : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestMX : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestUS : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestIT : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestAR : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTest979 : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestGB : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestBY : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestCN : NBPhoneMetaData +@end + +@interface NBPhoneMetadataTestRE : NBPhoneMetaData +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.m new file mode 100644 index 0000000000..1a4c042808 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTest.m @@ -0,0 +1,1662 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import "NBMetadataCoreTest.h" +#import "NBPhoneNumberDefines.h" +#import "NBPhoneNumberDesc.h" + +#import "NBNumberFormat.h" + +@implementation NBPhoneMetadataTestAD +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AD"; + self.countryCode = [NSNumber numberWithInteger:376]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestBR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BR"; + self.countryCode = [NSNumber numberWithInteger:55]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestAU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-578]\\d{4,14}" withPossibleNumberPattern:@"\\d{5,15}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2378]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"4\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1800\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"190[0126]\\d{6}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AU"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = @"001[12]"; + self.preferredInternationalPrefix = @"0011"; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[2-478]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{1})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestBB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BB"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestAE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"600\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"600123456"]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AE"; + self.countryCode = [NSNumber numberWithInteger:971]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestCX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CX"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestBS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(242|8(00|66|77|88)|900)\\d{7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"242(?:3(?:02|[236][1-9]|4[0-24-9]|5[0-68]|7[3-57]|9[2-5])|4(?:2[237]|51|64|77)|502|636|702)\\d{4}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"242(357|359|457|557)\\d{4}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(00|66|77|88)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BS"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestDE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{4,14}" withPossibleNumberPattern:@"\\d{2,14}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:[24-6]\\d{2}|3[03-9]\\d|[789](?:[1-9]\\d|0[2-9]))\\d{1,8}" withPossibleNumberPattern:@"\\d{2,14}" withExample:@"30123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1(5\\d{9}|7\\d{8}|6[02]\\d{8}|63\\d{7})" withPossibleNumberPattern:@"\\d{10,11}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900([135]\\d{6}|9\\d{7})" withPossibleNumberPattern:@"\\d{10,11}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"DE"; + self.countryCode = [NSNumber numberWithInteger:49]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"2|3[3-9]|906|[4-9][1-9]1"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,8})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[34]0|[68]9"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4,11})" withFormat:@"$1/$2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[4-9]"]; + [numberFormats2_patternArray addObject:@"[4-6]|[7-9](?:\\d[1-9]|[1-9]\\d)"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"([4-9]\\d)(\\d{2})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"[4-9]"]; + [numberFormats3_patternArray addObject:@"[4-6]|[7-9](?:\\d[1-9]|[1-9]\\d)"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"([4-9]\\d{3})(\\d{2,7})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{1})(\\d{6})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"900"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestKR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-7]\\d{3,9}|8\\d{8}" withPossibleNumberPattern:@"\\d{4,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:2|[34][1-3]|5[1-5]|6[1-4])(?:1\\d{2,3}|[2-9]\\d{6,7})" withPossibleNumberPattern:@"\\d{4,10}" withExample:@"22123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1[0-25-9]\\d{7,8}" withPossibleNumberPattern:@"\\d{9,10}" withExample:@"1023456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"60[2-9]\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"602345678"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"50\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"5012345678"]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:@"7012345678"]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"KR"; + self.countryCode = [NSNumber numberWithInteger:82]; + self.internationalPrefix = @"00(?:[124-68]|[37]\\d{2})"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0(8[1-46-8]|85\\d{2})?"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"1(?:0|1[19]|[69]9|5[458])|[57]0"]; + [numberFormats0_patternArray addObject:@"1(?:0|1[19]|[69]9|5(?:44|59|8))|[57]0"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1(?:[169][2-8]|[78]|5[1-4])|[68]0|[3-6][1-9][2-9]"]; + [numberFormats1_patternArray addObject:@"1(?:[169][2-8]|[78]|5(?:[1-3]|4[56]))|[68]0|[3-6][1-9][2-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"131"]; + [numberFormats2_patternArray addObject:@"1312"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d)(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"131"]; + [numberFormats3_patternArray addObject:@"131[13-9]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"13[2-9]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"30"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3-$4" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"2(?:[26]|3[0-467])"]; + [numberFormats6_patternArray addObject:@"2(?:[26]|3(?:01|1[45]|2[17-9]|39|4|6[67]|7[078]))"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + + NSMutableArray *numberFormats7_patternArray = [[NSMutableArray alloc] init]; + [numberFormats7_patternArray addObject:@"2(?:3[0-35-9]|[457-9])"]; + [numberFormats7_patternArray addObject:@"2(?:3(?:0[02-9]|1[0-36-9]|2[02-6]|3[0-8]|6[0-589]|7[1-69]|[589])|[457-9])"]; + NBNumberFormat *numberFormats7 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats7_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats7]; + + NSMutableArray *numberFormats8_patternArray = [[NSMutableArray alloc] init]; + [numberFormats8_patternArray addObject:@"21[0-46-9]"]; + [numberFormats8_patternArray addObject:@"21(?:[0-247-9]|3[124]|6[1269])"]; + NBNumberFormat *numberFormats8 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats8_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats8]; + + NSMutableArray *numberFormats9_patternArray = [[NSMutableArray alloc] init]; + [numberFormats9_patternArray addObject:@"21[36]"]; + [numberFormats9_patternArray addObject:@"21(?:3[035-9]|6[03-578])"]; + NBNumberFormat *numberFormats9 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats9_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats9]; + + NSMutableArray *numberFormats10_patternArray = [[NSMutableArray alloc] init]; + [numberFormats10_patternArray addObject:@"[3-6][1-9]1"]; + [numberFormats10_patternArray addObject:@"[3-6][1-9]1(?:[0-46-9])"]; + [numberFormats10_patternArray addObject:@"[3-6][1-9]1(?:[0-247-9]|3[124]|6[1269])"]; + NBNumberFormat *numberFormats10 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats10_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats10]; + + NSMutableArray *numberFormats11_patternArray = [[NSMutableArray alloc] init]; + [numberFormats11_patternArray addObject:@"[3-6][1-9]1"]; + [numberFormats11_patternArray addObject:@"[3-6][1-9]1[36]"]; + [numberFormats11_patternArray addObject:@"[3-6][1-9]1(?:3[035-9]|6[03-578])"]; + NBNumberFormat *numberFormats11 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats11_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats11]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestNZ +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[289]\\d{7,9}|[3-7]\\d{7}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"24099\\d{3}|(?:3[2-79]|[479][2-689]|6[235-9])\\d{6}" withPossibleNumberPattern:@"\\d{7,8}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2(?:[027]\\d{7}|9\\d{6,7}|1(?:0\\d{5,7}|[12]\\d{5,6}|[3-9]\\d{5})|4[1-9]\\d{6}|8\\d{7,8})" withPossibleNumberPattern:@"\\d{8,10}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6,7}" withPossibleNumberPattern:@"\\d{9,10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{6,7}" withPossibleNumberPattern:@"\\d{9,10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"NZ"; + self.countryCode = [NSNumber numberWithInteger:64]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"24|[34679]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{4})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"2[179]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3,5})" withFormat:@"$1-$2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[89]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestPL +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"(?:5[01]|6[069]|7[289]|88)\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"PL"; + self.countryCode = [NSNumber numberWithInteger:48]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestSE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SE"; + self.countryCode = [NSNumber numberWithInteger:46]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestCA +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CA"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestAO +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[29]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2\\d(?:[26-9]\\d|\\d[26-9])\\d{5}" withPossibleNumberPattern:@"\\d{9}" withExample:@"222123456"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[1-3]\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"923123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AO"; + self.countryCode = [NSNumber numberWithInteger:244]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0~0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0~0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTest800 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"12345678"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{8}" withPossibleNumberPattern:@"\\d{8}" withExample:@"12345678"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:800]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestYT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[268]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"2696[0-4]\\d{4}" withPossibleNumberPattern:@"\\d{9}" withExample:@"269601234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"639\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"639123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"YT"; + self.countryCode = [NSNumber numberWithInteger:262]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"269|639"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestFR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3\\d{6}" withPossibleNumberPattern:@"\\d{7}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"FR"; + self.countryCode = [NSNumber numberWithInteger:33]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestGG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GG"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestHU +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"30\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"HU"; + self.countryCode = [NSNumber numberWithInteger:36]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"06"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"06"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestSG +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13689]\\d{7,10}" withPossibleNumberPattern:@"\\d{8}|\\d{10,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[36]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[89]\\d{7}" withPossibleNumberPattern:@"\\d{8}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1?800\\d{7}" withPossibleNumberPattern:@"\\d{10,11}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1900\\d{7}" withPossibleNumberPattern:@"\\d{11}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"SG"; + self.countryCode = [NSNumber numberWithInteger:65]; + self.internationalPrefix = @"0[0-3][0-9]"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"777777"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[369]|8[1-9]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[89]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"800"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestJP +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"07\\d{5}|[1-357-9]\\d{3,10}" withPossibleNumberPattern:@"\\d{4,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"07\\d{5}|[1-357-9]\\d{3,10}" withPossibleNumberPattern:@"\\d{4,11}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"07\\d{5}|[1-357-9]\\d{3,10}" withPossibleNumberPattern:@"\\d{4,11}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0777[01]\\d{2}" withPossibleNumberPattern:@"\\d{7}" withExample:@"0777012"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[23]\\d{3}" withPossibleNumberPattern:@"\\d{4}" withExample:nil]; + self.codeID = @"JP"; + self.countryCode = [NSNumber numberWithInteger:81]; + self.internationalPrefix = @"010"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[57-9]0"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[57-9]0"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"111|222|333"]; + [numberFormats2_patternArray addObject:@"(?:111|222|333)1"]; + [numberFormats2_patternArray addObject:@"(?:111|222|333)11"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"222|333"]; + [numberFormats3_patternArray addObject:@"2221|3332"]; + [numberFormats3_patternArray addObject:@"22212|3332"]; + [numberFormats3_patternArray addObject:@"222120|3332"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d)(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[23]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + + NSMutableArray *numberFormats5_patternArray = [[NSMutableArray alloc] init]; + [numberFormats5_patternArray addObject:@"077"]; + NBNumberFormat *numberFormats5 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1-$2" withLeadingDigitsPatterns:numberFormats5_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats5]; + + NSMutableArray *numberFormats6_patternArray = [[NSMutableArray alloc] init]; + [numberFormats6_patternArray addObject:@"[23]"]; + NBNumberFormat *numberFormats6 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})" withFormat:@"*$1" withLeadingDigitsPatterns:numberFormats6_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats6]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestCC +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CC"; + self.countryCode = [NSNumber numberWithInteger:61]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestMX +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{9,10}" withPossibleNumberPattern:@"\\d{7,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[2-9]\\d{9}" withPossibleNumberPattern:@"\\d{7,10}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"1\\d{10}" withPossibleNumberPattern:@"\\d{11}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"MX"; + self.countryCode = [NSNumber numberWithInteger:52]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"01"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"01|04[45](\\d{10})"; + self.nationalPrefixTransformRule = @"1$1"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[89]00"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"33|55|81"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"1(?:33|55|81)"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{2})(\\d{4})(\\d{4})" withFormat:@"045 $2 $3 $4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"045 $2 $3 $4" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"[89]00"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"33|55|81"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:@"01 $1" whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"1(?:33|55|81)"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(1)(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestUS +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13-689]\\d{9}|2[0-35-9]\\d{8}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"1234567890"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13-689]\\d{9}|2[0-35-9]\\d{8}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"1234567890"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[13-689]\\d{9}|2[0-35-9]\\d{8}" withPossibleNumberPattern:@"\\d{7}(?:\\d{3})?" withExample:@"1234567890"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:00|66|77|88)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1234567890"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"900\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1234567890"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"800\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:@"1234567890"]; + self.codeID = @"US"; + self.countryCode = [NSNumber numberWithInteger:1]; + self.internationalPrefix = @"011"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"1"; + self.preferredExtnPrefix = @" extn. "; + self.nationalPrefixForParsing = @"1"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:YES withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = YES; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestIT +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[0389]\\d{5,10}" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"0\\d{9,10}" withPossibleNumberPattern:@"\\d{10,11}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"3\\d{8,9}" withPossibleNumberPattern:@"\\d{9,10}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80(?:0\\d{6}|3\\d{3})" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"89(?:2\\d{3}|9\\d{6})" withPossibleNumberPattern:@"\\d{6,9}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"IT"; + self.countryCode = [NSNumber numberWithInteger:39]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"0[26]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"0[13-57-9]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{4})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"3"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{3,4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = YES; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestAR +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-3689]\\d{9,10}" withPossibleNumberPattern:@"\\d{6,11}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-3]\\d{9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9\\d{10}|[1-3]\\d{9}" withPossibleNumberPattern:@"\\d{10,11}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(0\\d|10)\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"AR"; + self.countryCode = [NSNumber numberWithInteger:54]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0(?:(11|343|3715)15)?"; + self.nationalPrefixTransformRule = @"9$1"; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"11"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"1[02-9]|[23]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"911"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9)(11)(\\d{4})(\\d{4})" withFormat:@"$2 15 $3-$4" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"9(?:1[02-9]|[23])"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$2 $3-$4" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"0$1 $CC"]; + [numberFormats_FormatArray addObject:numberFormats3]; + + NSMutableArray *numberFormats4_patternArray = [[NSMutableArray alloc] init]; + [numberFormats4_patternArray addObject:@"[68]"]; + NBNumberFormat *numberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:numberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats4]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *intlNumberFormats0_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats0_patternArray addObject:@"11"]; + NBNumberFormat *intlNumberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats0]; + + NSMutableArray *intlNumberFormats1_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats1_patternArray addObject:@"1[02-9]|[23]"]; + NBNumberFormat *intlNumberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2-$3" withLeadingDigitsPatterns:intlNumberFormats1_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats1]; + + NSMutableArray *intlNumberFormats2_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats2_patternArray addObject:@"911"]; + NBNumberFormat *intlNumberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(9)(11)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats2_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats2]; + + NSMutableArray *intlNumberFormats3_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats3_patternArray addObject:@"9(?:1[02-9]|[23])"]; + NBNumberFormat *intlNumberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(9)(\\d{4})(\\d{2})(\\d{4})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:intlNumberFormats3_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats3]; + + NSMutableArray *intlNumberFormats4_patternArray = [[NSMutableArray alloc] init]; + [intlNumberFormats4_patternArray addObject:@"[68]"]; + NBNumberFormat *intlNumberFormats4 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1-$2-$3" withLeadingDigitsPatterns:intlNumberFormats4_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [intlNumberFormats_FormatArray addObject:intlNumberFormats4]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTest979 +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{9}" withExample:@"123456789"]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"123456789"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:@"123456789"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{9}" withPossibleNumberPattern:@"\\d{9}" withExample:@"123456789"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"001"; + self.countryCode = [NSNumber numberWithInteger:979]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:nil whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestGB +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"\\d{10}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-6]\\d{9}" withPossibleNumberPattern:@"\\d{6,10}" withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"7[1-57-9]\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"9[018]\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:4[3-5]|7[0-2])\\d{7}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"70\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"56\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"76\\d{8}" withPossibleNumberPattern:@"\\d{10}" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"GB"; + self.countryCode = [NSNumber numberWithInteger:44]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-59]|[78]0"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{4})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"6"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d)(\\d{3})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"7[1-57-9]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})(\\d{3})(\\d{3})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + + NSMutableArray *numberFormats3_patternArray = [[NSMutableArray alloc] init]; + [numberFormats3_patternArray addObject:@"8[47]"]; + NBNumberFormat *numberFormats3 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})(\\d{4})" withFormat:@"$1 $2 $3" withLeadingDigitsPatterns:numberFormats3_patternArray withNationalPrefixFormattingRule:@"(0$1)" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats3]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestBY +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:@"112345"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[1-9]\\d{5}" withPossibleNumberPattern:@"\\d{6}" withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"BY"; + self.countryCode = [NSNumber numberWithInteger:375]; + self.internationalPrefix = @"810"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"8"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"80?|99999"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[1-8]"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{4})" withFormat:@"$1" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + + NSMutableArray *numberFormats1_patternArray = [[NSMutableArray alloc] init]; + [numberFormats1_patternArray addObject:@"[1-8]"]; + NBNumberFormat *numberFormats1 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{2})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats1_patternArray withNationalPrefixFormattingRule:@"8$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats1]; + + NSMutableArray *numberFormats2_patternArray = [[NSMutableArray alloc] init]; + [numberFormats2_patternArray addObject:@"[1-8]"]; + NBNumberFormat *numberFormats2 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{3})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats2_patternArray withNationalPrefixFormattingRule:@"8 $1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats2]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestCN +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"CN"; + self.countryCode = [NSNumber numberWithInteger:86]; + self.internationalPrefix = nil; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = nil; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = nil; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = YES; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + [numberFormats0_patternArray addObject:@"[3-9]"]; + [numberFormats0_patternArray addObject:@"[3-9]\\d{2}[19]"]; + [numberFormats0_patternArray addObject:@"[3-9]\\d{2}(?:10|95)"]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"(\\d{3})(\\d{5,6})" withFormat:@"$1 $2" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:@"$CC $1"]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = nil; + self.leadingZeroPossible = NO; + } + return self; +} +@end + +@implementation NBPhoneMetadataTestRE +- (id)init +{ + self = [super init]; + if (self) { + self.generalDesc = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"[268]\\d{8}" withPossibleNumberPattern:@"\\d{9}" withExample:nil]; + self.fixedLine = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"262\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"262161234"]; + self.mobile = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"6(?:9[23]|47)\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"692123456"]; + self.tollFree = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"80\\d{7}" withPossibleNumberPattern:@"\\d{9}" withExample:@"801234567"]; + self.premiumRate = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"8(?:1[01]|2[0156]|84|9[0-37-9])\\d{6}" withPossibleNumberPattern:@"\\d{9}" withExample:@"810123456"]; + self.sharedCost = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.personalNumber = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.voip = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.pager = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.uan = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.emergency = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:nil withPossibleNumberPattern:nil withExample:nil]; + self.voicemail = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:@"NA" withPossibleNumberPattern:@"NA" withExample:nil]; + self.codeID = @"RE"; + self.countryCode = [NSNumber numberWithInteger:262]; + self.internationalPrefix = @"00"; + self.preferredInternationalPrefix = nil; + self.nationalPrefix = @"0"; + self.preferredExtnPrefix = nil; + self.nationalPrefixForParsing = @"0"; + self.nationalPrefixTransformRule = nil; + self.sameMobileAndFixedLinePattern = NO; + + NSMutableArray *numberFormats_FormatArray = [[NSMutableArray alloc] init]; + + NSMutableArray *numberFormats0_patternArray = [[NSMutableArray alloc] init]; + NBNumberFormat *numberFormats0 = [[NBNumberFormat alloc] initWithPattern:@"([268]\\d{2})(\\d{2})(\\d{2})(\\d{2})" withFormat:@"$1 $2 $3 $4" withLeadingDigitsPatterns:numberFormats0_patternArray withNationalPrefixFormattingRule:@"0$1" whenFormatting:NO withDomesticCarrierCodeFormattingRule:nil]; + [numberFormats_FormatArray addObject:numberFormats0]; + self.numberFormats = numberFormats_FormatArray; + + NSMutableArray *intlNumberFormats_FormatArray = [[NSMutableArray alloc] init]; + self.intlNumberFormats = intlNumberFormats_FormatArray; + self.mainCountryForCode = NO; + self.leadingDigits = @"262|6(?:9[23]|47)|8"; + self.leadingZeroPossible = NO; + } + return self; +} +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.h new file mode 100644 index 0000000000..e8735b6a98 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.h @@ -0,0 +1,10 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import + +@interface NBMetadataCoreTestMapper : NSObject + ++ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key; + +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.m new file mode 100644 index 0000000000..42805027af --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.m @@ -0,0 +1,122 @@ +// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) + +#import "NBMetadataCoreTestMapper.h" + +@implementation NBMetadataCoreTestMapper + +static NSMutableDictionary *kMapCCode2CN; + ++ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + kMapCCode2CN = [[NSMutableDictionary alloc] init]; + + NSMutableArray *countryCode971Array = [[NSMutableArray alloc] init]; + [countryCode971Array addObject:@"AE"]; + [kMapCCode2CN setObject:countryCode971Array forKey:@"971"]; + + NSMutableArray *countryCode55Array = [[NSMutableArray alloc] init]; + [countryCode55Array addObject:@"BR"]; + [kMapCCode2CN setObject:countryCode55Array forKey:@"55"]; + + NSMutableArray *countryCode48Array = [[NSMutableArray alloc] init]; + [countryCode48Array addObject:@"PL"]; + [kMapCCode2CN setObject:countryCode48Array forKey:@"48"]; + + NSMutableArray *countryCode33Array = [[NSMutableArray alloc] init]; + [countryCode33Array addObject:@"FR"]; + [kMapCCode2CN setObject:countryCode33Array forKey:@"33"]; + + NSMutableArray *countryCode49Array = [[NSMutableArray alloc] init]; + [countryCode49Array addObject:@"DE"]; + [kMapCCode2CN setObject:countryCode49Array forKey:@"49"]; + + NSMutableArray *countryCode86Array = [[NSMutableArray alloc] init]; + [countryCode86Array addObject:@"CN"]; + [kMapCCode2CN setObject:countryCode86Array forKey:@"86"]; + + NSMutableArray *countryCode64Array = [[NSMutableArray alloc] init]; + [countryCode64Array addObject:@"NZ"]; + [kMapCCode2CN setObject:countryCode64Array forKey:@"64"]; + + NSMutableArray *countryCode800Array = [[NSMutableArray alloc] init]; + [countryCode800Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode800Array forKey:@"800"]; + + NSMutableArray *countryCode1Array = [[NSMutableArray alloc] init]; + [countryCode1Array addObject:@"US"]; + [countryCode1Array addObject:@"BB"]; + [countryCode1Array addObject:@"BS"]; + [countryCode1Array addObject:@"CA"]; + [kMapCCode2CN setObject:countryCode1Array forKey:@"1"]; + + NSMutableArray *countryCode65Array = [[NSMutableArray alloc] init]; + [countryCode65Array addObject:@"SG"]; + [kMapCCode2CN setObject:countryCode65Array forKey:@"65"]; + + NSMutableArray *countryCode36Array = [[NSMutableArray alloc] init]; + [countryCode36Array addObject:@"HU"]; + [kMapCCode2CN setObject:countryCode36Array forKey:@"36"]; + + NSMutableArray *countryCode244Array = [[NSMutableArray alloc] init]; + [countryCode244Array addObject:@"AO"]; + [kMapCCode2CN setObject:countryCode244Array forKey:@"244"]; + + NSMutableArray *countryCode375Array = [[NSMutableArray alloc] init]; + [countryCode375Array addObject:@"BY"]; + [kMapCCode2CN setObject:countryCode375Array forKey:@"375"]; + + NSMutableArray *countryCode44Array = [[NSMutableArray alloc] init]; + [countryCode44Array addObject:@"GB"]; + [countryCode44Array addObject:@"GG"]; + [kMapCCode2CN setObject:countryCode44Array forKey:@"44"]; + + NSMutableArray *countryCode81Array = [[NSMutableArray alloc] init]; + [countryCode81Array addObject:@"JP"]; + [kMapCCode2CN setObject:countryCode81Array forKey:@"81"]; + + NSMutableArray *countryCode52Array = [[NSMutableArray alloc] init]; + [countryCode52Array addObject:@"MX"]; + [kMapCCode2CN setObject:countryCode52Array forKey:@"52"]; + + NSMutableArray *countryCode82Array = [[NSMutableArray alloc] init]; + [countryCode82Array addObject:@"KR"]; + [kMapCCode2CN setObject:countryCode82Array forKey:@"82"]; + + NSMutableArray *countryCode376Array = [[NSMutableArray alloc] init]; + [countryCode376Array addObject:@"AD"]; + [kMapCCode2CN setObject:countryCode376Array forKey:@"376"]; + + NSMutableArray *countryCode979Array = [[NSMutableArray alloc] init]; + [countryCode979Array addObject:@"001"]; + [kMapCCode2CN setObject:countryCode979Array forKey:@"979"]; + + NSMutableArray *countryCode46Array = [[NSMutableArray alloc] init]; + [countryCode46Array addObject:@"SE"]; + [kMapCCode2CN setObject:countryCode46Array forKey:@"46"]; + + NSMutableArray *countryCode39Array = [[NSMutableArray alloc] init]; + [countryCode39Array addObject:@"IT"]; + [kMapCCode2CN setObject:countryCode39Array forKey:@"39"]; + + NSMutableArray *countryCode61Array = [[NSMutableArray alloc] init]; + [countryCode61Array addObject:@"AU"]; + [countryCode61Array addObject:@"CC"]; + [countryCode61Array addObject:@"CX"]; + [kMapCCode2CN setObject:countryCode61Array forKey:@"61"]; + + NSMutableArray *countryCode54Array = [[NSMutableArray alloc] init]; + [countryCode54Array addObject:@"AR"]; + [kMapCCode2CN setObject:countryCode54Array forKey:@"54"]; + + NSMutableArray *countryCode262Array = [[NSMutableArray alloc] init]; + [countryCode262Array addObject:@"RE"]; + [countryCode262Array addObject:@"YT"]; + [kMapCCode2CN setObject:countryCode262Array forKey:@"262"]; + }); + return [kMapCCode2CN objectForKey:key]; +} + +@end + diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.h new file mode 100644 index 0000000000..0429601295 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.h @@ -0,0 +1,32 @@ +// +// NBMetadataHelper.h +// libPhoneNumber +// +// Created by tabby on 2015. 2. 8.. +// Copyright (c) 2015년 ohtalk.me. All rights reserved. +// + +#import +#import "NBPhoneNumberDefines.h" + + +@class NBPhoneMetaData; + +@interface NBMetadataHelper : NSObject + ++ (BOOL)hasValue:(NSString *)string; + +- (NSDictionary *)CCode2CNMap; + +- (NSArray *)getAllMetadata; + +- (NBPhoneMetaData *)getMetadataForNonGeographicalRegion:(NSNumber *)countryCallingCode; +- (NBPhoneMetaData *)getMetadataForRegion:(NSString *)regionCode; + +- (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber; +- (NSString *)countryCodeFromRegionCode:(NSString *)regionCode; + +- (NSString *)stringByTrimming:(NSString *)aString; +- (NSString *)normalizeNonBreakingSpace:(NSString *)aString; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.m new file mode 100644 index 0000000000..40c933eb90 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBMetadataHelper.m @@ -0,0 +1,273 @@ +// +// NBMetadataHelper.m +// libPhoneNumber +// +// Created by tabby on 2015. 2. 8.. +// Copyright (c) 2015년 ohtalk.me. All rights reserved. +// + +#import "NBMetadataHelper.h" +#import "NBPhoneMetaData.h" +#import "NBMetadataCore.h" + + +#if TESTING==1 +#define NB_CLASS_PREFIX @"NBPhoneMetadataTest" +#import "NBMetadataCoreTest.h" +#import "NBMetadataCoreTestMapper.h" +#else +#define NB_CLASS_PREFIX @"NBPhoneMetadata" +#import "NBMetadataCore.h" +#import "NBMetadataCoreMapper.h" +#endif + + +@interface NBMetadataHelper () + +// Cached metadata +@property(nonatomic, strong) NBPhoneMetaData *cachedMetaData; +@property(nonatomic, strong) NSString *cachedMetaDataKey; + +@end + + +@implementation NBMetadataHelper + +/* + Terminologies + - Country Number (CN) = Country code for i18n calling + - Country Code (CC) : ISO country codes (2 chars) + Ref. site (countrycode.org) + */ + +static NSMutableDictionary *kMapCCode2CN = nil; + +/** + * initialization meta-meta variables + */ +- (void)initializeHelper +{ + if (!NBPhoneMetadataAM.class) // force linkage of NBMetadataCore.m + return; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + kMapCCode2CN = [NSMutableDictionary dictionaryWithObjectsAndKeys: + @"1", @"US", @"1", @"AG", @"1", @"AI", @"1", @"AS", @"1", @"BB", @"1", @"BM", @"1", @"BS", @"1", @"CA", @"1", @"DM", @"1", @"DO", + @"1", @"GD", @"1", @"GU", @"1", @"JM", @"1", @"KN", @"1", @"KY", @"1", @"LC", @"1", @"MP", @"1", @"MS", @"1", @"PR", @"1", @"SX", + @"1", @"TC", @"1", @"TT", @"1", @"VC", @"1", @"VG", @"1", @"VI", @"7", @"RU", @"7", @"KZ", + @"20", @"EG", @"27", @"ZA", + @"30", @"GR", @"31", @"NL", @"32", @"BE", @"33", @"FR", @"34", @"ES", @"36", @"HU", @"39", @"IT", + @"40", @"RO", @"41", @"CH", @"43", @"AT", @"44", @"GB", @"44", @"GG", @"44", @"IM", @"44", @"JE", @"45", @"DK", @"46", @"SE", @"47", @"NO", @"47", @"SJ", @"48", @"PL", @"49", @"DE", + @"51", @"PE", @"52", @"MX", @"53", @"CU", @"54", @"AR", @"55", @"BR", @"56", @"CL", @"57", @"CO", @"58", @"VE", + @"60", @"MY", @"61", @"AU", @"61", @"CC", @"61", @"CX", @"62", @"ID", @"63", @"PH", @"64", @"NZ", @"65", @"SG", @"66", @"TH", + @"81", @"JP", @"82", @"KR", @"84", @"VN", @"86", @"CN", + @"90", @"TR", @"91", @"IN", @"92", @"PK", @"93", @"AF", @"94", @"LK", @"95", @"MM", @"98", @"IR", + @"211", @"SS", @"212", @"MA", @"212", @"EH", @"213", @"DZ", @"216", @"TN", @"218", @"LY", + @"220", @"GM", @"221", @"SN", @"222", @"MR", @"223", @"ML", @"224", @"GN", @"225", @"CI", @"226", @"BF", @"227", @"NE", @"228", @"TG", @"229", @"BJ", + @"230", @"MU", @"231", @"LR", @"232", @"SL", @"233", @"GH", @"234", @"NG", @"235", @"TD", @"236", @"CF", @"237", @"CM", @"238", @"CV", @"239", @"ST", + @"240", @"GQ", @"241", @"GA", @"242", @"CG", @"243", @"CD", @"244", @"AO", @"245", @"GW", @"246", @"IO", @"247", @"AC", @"248", @"SC", @"249", @"SD", + @"250", @"RW", @"251", @"ET", @"252", @"SO", @"253", @"DJ", @"254", @"KE", @"255", @"TZ", @"256", @"UG", @"257", @"BI", @"258", @"MZ", + @"260", @"ZM", @"261", @"MG", @"262", @"RE", @"262", @"YT", @"263", @"ZW", @"264", @"NA", @"265", @"MW", @"266", @"LS", @"267", @"BW", @"268", @"SZ", @"269", @"KM", + @"290", @"SH", @"291", @"ER", @"297", @"AW", @"298", @"FO", @"299", @"GL", + @"350", @"GI", @"351", @"PT", @"352", @"LU", @"353", @"IE", @"354", @"IS", @"355", @"AL", @"356", @"MT", @"357", @"CY", @"358", @"FI",@"358", @"AX", @"359", @"BG", + @"370", @"LT", @"371", @"LV", @"372", @"EE", @"373", @"MD", @"374", @"AM", @"375", @"BY", @"376", @"AD", @"377", @"MC", @"378", @"SM", @"379", @"VA", + @"380", @"UA", @"381", @"RS", @"382", @"ME", @"385", @"HR", @"386", @"SI", @"387", @"BA", @"389", @"MK", + @"420", @"CZ", @"421", @"SK", @"423", @"LI", + @"500", @"FK", @"501", @"BZ", @"502", @"GT", @"503", @"SV", @"504", @"HN", @"505", @"NI", @"506", @"CR", @"507", @"PA", @"508", @"PM", @"509", @"HT", + @"590", @"GP", @"590", @"BL", @"590", @"MF", @"591", @"BO", @"592", @"GY", @"593", @"EC", @"594", @"GF", @"595", @"PY", @"596", @"MQ", @"597", @"SR", @"598", @"UY", @"599", @"CW", @"599", @"BQ", + @"670", @"TL", @"672", @"NF", @"673", @"BN", @"674", @"NR", @"675", @"PG", @"676", @"TO", @"677", @"SB", @"678", @"VU", @"679", @"FJ", + @"680", @"PW", @"681", @"WF", @"682", @"CK", @"683", @"NU", @"685", @"WS", @"686", @"KI", @"687", @"NC", @"688", @"TV", @"689", @"PF", + @"690", @"TK", @"691", @"FM", @"692", @"MH", + @"800", @"001", @"808", @"001", + @"850", @"KP", @"852", @"HK", @"853", @"MO", @"855", @"KH", @"856", @"LA", + @"870", @"001", @"878", @"001", + @"880", @"BD", @"881", @"001", @"882", @"001", @"883", @"001", @"886", @"TW", @"888", @"001", + @"960", @"MV", @"961", @"LB", @"962", @"JO", @"963", @"SY", @"964", @"IQ", @"965", @"KW", @"966", @"SA", @"967", @"YE", @"968", @"OM", + @"970", @"PS", @"971", @"AE", @"972", @"IL", @"973", @"BH", @"974", @"QA", @"975", @"BT", @"976", @"MN", @"977", @"NP", @"979", @"001", + @"992", @"TJ", @"993", @"TM", @"994", @"AZ", @"995", @"GE", @"996", @"KG", @"998", @"UZ", + nil]; + }); +} + +- (NSDictionary *)CCode2CNMap{ + if (!kMapCCode2CN){ + [self initializeHelper]; + } + return kMapCCode2CN; +} + +- (void)clearHelper +{ + if (kMapCCode2CN) { + [kMapCCode2CN removeAllObjects]; + kMapCCode2CN = nil; + } +} + + +- (NSArray*)getAllMetadata +{ + NSArray *countryCodes = [NSLocale ISOCountryCodes]; + NSMutableArray *resultMetadata = [[NSMutableArray alloc] init]; + + for (NSString *countryCode in countryCodes) { + id countryDictionaryInstance = [NSDictionary dictionaryWithObject:countryCode forKey:NSLocaleCountryCode]; + NSString *identifier = [NSLocale localeIdentifierFromComponents:countryDictionaryInstance]; + NSString *country = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:identifier]; + + NSMutableDictionary *countryMeta = [[NSMutableDictionary alloc] init]; + if (country) { + [countryMeta setObject:country forKey:@"name"]; + } + + if (countryCode) { + [countryMeta setObject:countryCode forKey:@"code"]; + } + + NBPhoneMetaData *metaData = [self getMetadataForRegion:countryCode]; + if (metaData) { + [countryMeta setObject:metaData forKey:@"metadata"]; + } + + [resultMetadata addObject:countryMeta]; + } + + return resultMetadata; +} + + +- (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber +{ + [self initializeHelper]; + + id res = nil; + +#if TESTING==1 + res = [NBMetadataCoreTestMapper ISOCodeFromCallingNumber:[countryCodeNumber stringValue]]; +#else + res = [NBMetadataCoreMapper ISOCodeFromCallingNumber:[countryCodeNumber stringValue]]; +#endif + + if (res && [res isKindOfClass:[NSArray class]] && [((NSArray*)res) count] > 0) { + return res; + } + + return nil; +} + + +- (NSString *)countryCodeFromRegionCode:(NSString* )regionCode +{ + [self initializeHelper]; + + id res = [kMapCCode2CN objectForKey:regionCode]; + + if (res) { + return res; + } + + return nil; +} + + +- (NSString *)stringByTrimming:(NSString *)aString +{ + if (aString == nil || aString.length <= 0) return aString; + + aString = [self normalizeNonBreakingSpace:aString]; + + NSString *aRes = @""; + NSArray *newlines = [aString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + for (NSString *line in newlines) { + NSString *performedString = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if (performedString.length > 0) { + aRes = [aRes stringByAppendingString:performedString]; + } + } + + if (newlines.count <= 0) { + return aString; + } + + return aRes; +} + + +- (NSString *)normalizeNonBreakingSpace:(NSString *)aString +{ + return [aString stringByReplacingOccurrencesOfString:NB_NON_BREAKING_SPACE withString:@" "]; +} + + +/** + * Returns the metadata for the given region code or {@code nil} if the region + * code is invalid or unknown. + * + * @param {?string} regionCode + * @return {i18n.phonenumbers.PhoneMetadata} + */ +- (NBPhoneMetaData *)getMetadataForRegion:(NSString *)regionCode +{ + [self initializeHelper]; + + if ([NBMetadataHelper hasValue:regionCode] == NO) { + return nil; + } + + regionCode = [regionCode uppercaseString]; + + if (_cachedMetaDataKey && [_cachedMetaDataKey isEqualToString:regionCode]) { + return _cachedMetaData; + } + + NSString *className = [NSString stringWithFormat:@"%@%@", NB_CLASS_PREFIX, regionCode]; + + Class metaClass = NSClassFromString(className); + + if (metaClass) { + NBPhoneMetaData *metadata = [[metaClass alloc] init]; + + _cachedMetaData = metadata; + _cachedMetaDataKey = regionCode; + + return metadata; + } + + return nil; +} + + +/** + * @param {number} countryCallingCode + * @return {i18n.phonenumbers.PhoneMetadata} + */ +- (NBPhoneMetaData *)getMetadataForNonGeographicalRegion:(NSNumber *)countryCallingCode +{ + NSString *countryCallingCodeStr = [NSString stringWithFormat:@"%@", countryCallingCode]; + return [self getMetadataForRegion:countryCallingCodeStr]; +} + + +#pragma mark - Regular expression Utilities - + ++ (BOOL)hasValue:(NSString*)string +{ + static dispatch_once_t onceToken; + static NSCharacterSet *whitespaceCharSet = nil; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *spaceCharSet = [NSMutableCharacterSet characterSetWithCharactersInString:NB_NON_BREAKING_SPACE]; + [spaceCharSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + whitespaceCharSet = spaceCharSet; + }); + + if (string == nil || [string stringByTrimmingCharactersInSet:whitespaceCharSet].length <= 0) { + return NO; + } + + return YES; +} + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.h new file mode 100755 index 0000000000..2abb41afef --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.h @@ -0,0 +1,22 @@ +// +// NBPhoneNumberFormat.h +// libPhoneNumber +// +// + +#import + + +@interface NBNumberFormat : NSObject + +// from phonemetadata.pb.js +/* 1 */ @property (nonatomic, strong) NSString *pattern; +/* 2 */ @property (nonatomic, strong) NSString *format; +/* 3 */ @property (nonatomic, strong) NSMutableArray *leadingDigitsPatterns; +/* 4 */ @property (nonatomic, strong) NSString *nationalPrefixFormattingRule; +/* 6 */ @property (nonatomic, assign) BOOL nationalPrefixOptionalWhenFormatting; +/* 5 */ @property (nonatomic, strong) NSString *domesticCarrierCodeFormattingRule; + +- (id)initWithPattern:(NSString *)pattern withFormat:(NSString *)format withLeadingDigitsPatterns:(NSMutableArray *)leadingDigitsPatterns withNationalPrefixFormattingRule:(NSString *)nationalPrefixFormattingRule whenFormatting:(BOOL)nationalPrefixOptionalWhenFormatting withDomesticCarrierCodeFormattingRule:(NSString *)domesticCarrierCodeFormattingRule; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.m new file mode 100755 index 0000000000..cad8771025 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBNumberFormat.m @@ -0,0 +1,97 @@ +// +// NBPhoneNumberFormat.m +// libPhoneNumber +// +// + +#import "NBNumberFormat.h" + + +@implementation NBNumberFormat + + +- (id)initWithPattern:(NSString *)pattern withFormat:(NSString *)format withLeadingDigitsPatterns:(NSMutableArray *)leadingDigitsPatterns withNationalPrefixFormattingRule:(NSString *)nationalPrefixFormattingRule whenFormatting:(BOOL)nationalPrefixOptionalWhenFormatting withDomesticCarrierCodeFormattingRule:(NSString *)domesticCarrierCodeFormattingRule +{ + self = [self init]; + + _pattern = pattern; + _format = format; + _leadingDigitsPatterns = leadingDigitsPatterns; + _nationalPrefixFormattingRule = nationalPrefixFormattingRule; + _nationalPrefixOptionalWhenFormatting = nationalPrefixOptionalWhenFormatting; + _domesticCarrierCodeFormattingRule = domesticCarrierCodeFormattingRule; + + return self; +} + + +- (id)init +{ + self = [super init]; + + if (self) { + self.nationalPrefixOptionalWhenFormatting = NO; + self.leadingDigitsPatterns = [[NSMutableArray alloc] init]; + } + + return self; +} + + +- (NSString *)description +{ + return [NSString stringWithFormat:@"[pattern:%@, format:%@, leadingDigitsPattern:%@, nationalPrefixFormattingRule:%@, nationalPrefixOptionalWhenFormatting:%@, domesticCarrierCodeFormattingRule:%@]", + self.pattern, self.format, self.leadingDigitsPatterns, self.nationalPrefixFormattingRule, self.nationalPrefixOptionalWhenFormatting?@"Y":@"N", self.domesticCarrierCodeFormattingRule]; +} + + +- (id)copyWithZone:(NSZone *)zone +{ + NBNumberFormat *phoneFormatCopy = [[NBNumberFormat allocWithZone:zone] init]; + + /* + 1 @property (nonatomic, strong, readwrite) NSString *pattern; + 2 @property (nonatomic, strong, readwrite) NSString *format; + 3 @property (nonatomic, strong, readwrite) NSString *leadingDigitsPattern; + 4 @property (nonatomic, strong, readwrite) NSString *nationalPrefixFormattingRule; + 6 @property (nonatomic, assign, readwrite) BOOL nationalPrefixOptionalWhenFormatting; + 5 @property (nonatomic, strong, readwrite) NSString *domesticCarrierCodeFormattingRule; + */ + + phoneFormatCopy.pattern = [self.pattern copy]; + phoneFormatCopy.format = [self.format copy]; + phoneFormatCopy.leadingDigitsPatterns = [self.leadingDigitsPatterns copy]; + phoneFormatCopy.nationalPrefixFormattingRule = [self.nationalPrefixFormattingRule copy]; + phoneFormatCopy.nationalPrefixOptionalWhenFormatting = self.nationalPrefixOptionalWhenFormatting; + phoneFormatCopy.domesticCarrierCodeFormattingRule = [self.domesticCarrierCodeFormattingRule copy]; + + return phoneFormatCopy; +} + + +- (id)initWithCoder:(NSCoder*)coder +{ + if (self = [super init]) { + self.pattern = [coder decodeObjectForKey:@"pattern"]; + self.format = [coder decodeObjectForKey:@"format"]; + self.leadingDigitsPatterns = [coder decodeObjectForKey:@"leadingDigitsPatterns"]; + self.nationalPrefixFormattingRule = [coder decodeObjectForKey:@"nationalPrefixFormattingRule"]; + self.nationalPrefixOptionalWhenFormatting = [[coder decodeObjectForKey:@"nationalPrefixOptionalWhenFormatting"] boolValue]; + self.domesticCarrierCodeFormattingRule = [coder decodeObjectForKey:@"domesticCarrierCodeFormattingRule"]; + } + return self; +} + + +- (void)encodeWithCoder:(NSCoder*)coder +{ + [coder encodeObject:self.pattern forKey:@"pattern"]; + [coder encodeObject:self.format forKey:@"format"]; + [coder encodeObject:self.leadingDigitsPatterns forKey:@"leadingDigitsPatterns"]; + [coder encodeObject:self.nationalPrefixFormattingRule forKey:@"nationalPrefixFormattingRule"]; + [coder encodeObject:[NSNumber numberWithBool:self.nationalPrefixOptionalWhenFormatting] forKey:@"nationalPrefixOptionalWhenFormatting"]; + [coder encodeObject:self.domesticCarrierCodeFormattingRule forKey:@"domesticCarrierCodeFormattingRule"]; +} + + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.h new file mode 100755 index 0000000000..6b0bf2ea1c --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.h @@ -0,0 +1,43 @@ +// +// M2PhoneMetaData.h +// libPhoneNumber +// +// + +#import + + +@class NBPhoneNumberDesc, NBNumberFormat; + +@interface NBPhoneMetaData : NSObject + +// from phonemetadata.pb.js +/* 1 */ @property (nonatomic, strong) NBPhoneNumberDesc *generalDesc; +/* 2 */ @property (nonatomic, strong) NBPhoneNumberDesc *fixedLine; +/* 3 */ @property (nonatomic, strong) NBPhoneNumberDesc *mobile; +/* 4 */ @property (nonatomic, strong) NBPhoneNumberDesc *tollFree; +/* 5 */ @property (nonatomic, strong) NBPhoneNumberDesc *premiumRate; +/* 6 */ @property (nonatomic, strong) NBPhoneNumberDesc *sharedCost; +/* 7 */ @property (nonatomic, strong) NBPhoneNumberDesc *personalNumber; +/* 8 */ @property (nonatomic, strong) NBPhoneNumberDesc *voip; +/* 21 */ @property (nonatomic, strong) NBPhoneNumberDesc *pager; +/* 25 */ @property (nonatomic, strong) NBPhoneNumberDesc *uan; +/* 27 */ @property (nonatomic, strong) NBPhoneNumberDesc *emergency; +/* 28 */ @property (nonatomic, strong) NBPhoneNumberDesc *voicemail; +/* 24 */ @property (nonatomic, strong) NBPhoneNumberDesc *noInternationalDialling; +/* 9 */ @property (nonatomic, strong) NSString *codeID; +/* 10 */ @property (nonatomic, strong) NSNumber *countryCode; +/* 11 */ @property (nonatomic, strong) NSString *internationalPrefix; +/* 17 */ @property (nonatomic, strong) NSString *preferredInternationalPrefix; +/* 12 */ @property (nonatomic, strong) NSString *nationalPrefix; +/* 13 */ @property (nonatomic, strong) NSString *preferredExtnPrefix; +/* 15 */ @property (nonatomic, strong) NSString *nationalPrefixForParsing; +/* 16 */ @property (nonatomic, strong) NSString *nationalPrefixTransformRule; +/* 18 */ @property (nonatomic, assign) BOOL sameMobileAndFixedLinePattern; +/* 19 */ @property (nonatomic, strong) NSMutableArray *numberFormats; +/* 20 */ @property (nonatomic, strong) NSMutableArray *intlNumberFormats; +/* 22 */ @property (nonatomic, assign) BOOL mainCountryForCode; +/* 23 */ @property (nonatomic, strong) NSString *leadingDigits; +/* 26 */ @property (nonatomic, assign) BOOL leadingZeroPossible; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.m new file mode 100755 index 0000000000..39e550a55a --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaData.m @@ -0,0 +1,105 @@ +// +// NBPhoneMetaData.m +// libPhoneNumber +// +// + +#import "NBPhoneMetaData.h" +#import "NBPhoneNumberDesc.h" +#import "NBNumberFormat.h" + + +@implementation NBPhoneMetaData + + +- (id)init +{ + self = [super init]; + + if (self) { + _numberFormats = [[NSMutableArray alloc] init]; + _intlNumberFormats = [[NSMutableArray alloc] init]; + + _leadingZeroPossible = NO; + _mainCountryForCode = NO; + } + + return self; +} + + +- (NSString *)description +{ + return [NSString stringWithFormat:@"* codeID[%@] countryCode[%@] generalDesc[%@] fixedLine[%@] mobile[%@] tollFree[%@] premiumRate[%@] sharedCost[%@] personalNumber[%@] voip[%@] pager[%@] uan[%@] emergency[%@] voicemail[%@] noInternationalDialling[%@] internationalPrefix[%@] preferredInternationalPrefix[%@] nationalPrefix[%@] preferredExtnPrefix[%@] nationalPrefixForParsing[%@] nationalPrefixTransformRule[%@] sameMobileAndFixedLinePattern[%@] numberFormats[%@] intlNumberFormats[%@] mainCountryForCode[%@] leadingDigits[%@] leadingZeroPossible[%@]", + _codeID, _countryCode, _generalDesc, _fixedLine, _mobile, _tollFree, _premiumRate, _sharedCost, _personalNumber, _voip, _pager, _uan, _emergency, _voicemail, _noInternationalDialling, _internationalPrefix, _preferredInternationalPrefix, _nationalPrefix, _preferredExtnPrefix, _nationalPrefixForParsing, _nationalPrefixTransformRule, _sameMobileAndFixedLinePattern?@"Y":@"N", _numberFormats, _intlNumberFormats, _mainCountryForCode?@"Y":@"N", _leadingDigits, _leadingZeroPossible?@"Y":@"N"]; +} + + +- (id)initWithCoder:(NSCoder*)coder +{ + if (self = [super init]) { + _generalDesc = [coder decodeObjectForKey:@"generalDesc"]; + _fixedLine = [coder decodeObjectForKey:@"fixedLine"]; + _mobile = [coder decodeObjectForKey:@"mobile"]; + _tollFree = [coder decodeObjectForKey:@"tollFree"]; + _premiumRate = [coder decodeObjectForKey:@"premiumRate"]; + _sharedCost = [coder decodeObjectForKey:@"sharedCost"]; + _personalNumber = [coder decodeObjectForKey:@"personalNumber"]; + _voip = [coder decodeObjectForKey:@"voip"]; + _pager = [coder decodeObjectForKey:@"pager"]; + _uan = [coder decodeObjectForKey:@"uan"]; + _emergency = [coder decodeObjectForKey:@"emergency"]; + _voicemail = [coder decodeObjectForKey:@"voicemail"]; + _noInternationalDialling = [coder decodeObjectForKey:@"noInternationalDialling"]; + _codeID = [coder decodeObjectForKey:@"codeID"]; + _countryCode = [coder decodeObjectForKey:@"countryCode"]; + _internationalPrefix = [coder decodeObjectForKey:@"internationalPrefix"]; + _preferredInternationalPrefix = [coder decodeObjectForKey:@"preferredInternationalPrefix"]; + _nationalPrefix = [coder decodeObjectForKey:@"nationalPrefix"]; + _preferredExtnPrefix = [coder decodeObjectForKey:@"preferredExtnPrefix"]; + _nationalPrefixForParsing = [coder decodeObjectForKey:@"nationalPrefixForParsing"]; + _nationalPrefixTransformRule = [coder decodeObjectForKey:@"nationalPrefixTransformRule"]; + _sameMobileAndFixedLinePattern = [[coder decodeObjectForKey:@"sameMobileAndFixedLinePattern"] boolValue]; + _numberFormats = [coder decodeObjectForKey:@"numberFormats"]; + _intlNumberFormats = [coder decodeObjectForKey:@"intlNumberFormats"]; + _mainCountryForCode = [[coder decodeObjectForKey:@"mainCountryForCode"] boolValue]; + _leadingDigits = [coder decodeObjectForKey:@"leadingDigits"]; + _leadingZeroPossible = [[coder decodeObjectForKey:@"leadingZeroPossible"] boolValue]; + } + return self; +} + + +- (void)encodeWithCoder:(NSCoder*)coder +{ + [coder encodeObject:_generalDesc forKey:@"generalDesc"]; + [coder encodeObject:_fixedLine forKey:@"fixedLine"]; + [coder encodeObject:_mobile forKey:@"mobile"]; + [coder encodeObject:_tollFree forKey:@"tollFree"]; + [coder encodeObject:_premiumRate forKey:@"premiumRate"]; + [coder encodeObject:_sharedCost forKey:@"sharedCost"]; + [coder encodeObject:_personalNumber forKey:@"personalNumber"]; + [coder encodeObject:_voip forKey:@"voip"]; + [coder encodeObject:_pager forKey:@"pager"]; + [coder encodeObject:_uan forKey:@"uan"]; + [coder encodeObject:_emergency forKey:@"emergency"]; + [coder encodeObject:_voicemail forKey:@"voicemail"]; + [coder encodeObject:_noInternationalDialling forKey:@"noInternationalDialling"]; + [coder encodeObject:_codeID forKey:@"codeID"]; + [coder encodeObject:_countryCode forKey:@"countryCode"]; + [coder encodeObject:_internationalPrefix forKey:@"internationalPrefix"]; + [coder encodeObject:_preferredInternationalPrefix forKey:@"preferredInternationalPrefix"]; + [coder encodeObject:_nationalPrefix forKey:@"nationalPrefix"]; + [coder encodeObject:_preferredExtnPrefix forKey:@"preferredExtnPrefix"]; + [coder encodeObject:_nationalPrefixForParsing forKey:@"nationalPrefixForParsing"]; + [coder encodeObject:_nationalPrefixTransformRule forKey:@"nationalPrefixTransformRule"]; + [coder encodeObject:[NSNumber numberWithBool:_sameMobileAndFixedLinePattern] forKey:@"sameMobileAndFixedLinePattern"]; + [coder encodeObject:_numberFormats forKey:@"numberFormats"]; + [coder encodeObject:_intlNumberFormats forKey:@"intlNumberFormats"]; + [coder encodeObject:[NSNumber numberWithBool:_mainCountryForCode] forKey:@"mainCountryForCode"]; + [coder encodeObject:_leadingDigits forKey:@"leadingDigits"]; + [coder encodeObject:[NSNumber numberWithBool:_leadingZeroPossible] forKey:@"leadingZeroPossible"]; +} + + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.h new file mode 100755 index 0000000000..2a32bc805c --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.h @@ -0,0 +1,14 @@ +// +// NBPhoneMetaDataGenerator.h +// libPhoneNumber +// +// + +#import + + +@interface NBPhoneMetaDataGenerator : NSObject + +- (void)generateMetadataClasses; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.m new file mode 100755 index 0000000000..21078e89c1 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.m @@ -0,0 +1,416 @@ +// +// NBPhoneMetaDataGenerator.m +// libPhoneNumber +// +// + +#import "NBPhoneMetaDataGenerator.h" +#import "NBPhoneMetaData.h" + +@interface NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index; +@end + +@implementation NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index { + @synchronized(self) { + if (index >= [self count]) return nil; + id res = [self objectAtIndex:index]; + if (res == nil || (NSNull*)res == [NSNull null]) { + return nil; + } + return res; + } +} +@end + +#define kNBSRCDirectoryName @"src" + +#define INDENT_TAB @" " +#define STR_VAL(val) [self stringForSourceCode:val] +#define NUM_VAL(val) [self numberForSourceCode:val] + +NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +@implementation NBPhoneMetaDataGenerator + + +- (id)init +{ + self = [super init]; + + if (self) + { + } + + return self; +} + + + + + + +- (void)generateMetadataClasses +{ + NSDictionary *realMetadata = [self generateMetaData]; + NSDictionary *testMetadata = [self generateMetaDataWithTest]; + + @try { + NSURL *dataPathURL= [NSURL fileURLWithPath: [self getSRCDirectoryPath]]; + NSError *error = nil; + BOOL success = [dataPathURL setResourceValue: @YES forKey: NSURLIsExcludedFromBackupKey error: &error]; + if(!success){ + NSLog(@"Error excluding %@ from backup %@", [dataPathURL lastPathComponent], error); + } + if (![[NSFileManager defaultManager] fileExistsAtPath:[dataPathURL path]]) { + BOOL sucess = [[NSFileManager defaultManager] createDirectoryAtURL:dataPathURL withIntermediateDirectories:NO attributes:nil error:&error]; + if(!sucess) { + NSLog(@"[%@] ERROR: attempting to write create MyFolder directory", [self class]); + } + } + + NSDictionary *mappedRealData = [self mappingObject:realMetadata]; + NSDictionary *mappedTestData = [self mappingObject:testMetadata]; + + [self createClassWithDictionary:mappedRealData name:@"NBMetadataCore" isTestData:NO]; + [self createClassWithDictionary:mappedTestData name:@"NBMetadataCoreTest" isTestData:YES]; + } @catch (NSException *exception) { + NSLog(@"Error for creating metadata classes : %@", exception.reason); + } +} + + +- (void)createClassWithDictionary:(NSDictionary*)data name:(NSString*)name isTestData:(BOOL)isTest +{ + NSString *dataPath = [self getSRCDirectoryPath]; + + NSString *codeStringHeader = [self generateSourceCodeWith:data name:name type:0 isTestData:isTest]; + NSString *codeStringSource = [self generateSourceCodeWith:data name:name type:1 isTestData:isTest]; + NSString *headerFilePath = [NSString stringWithFormat:@"%@/%@.h", dataPath, name]; + NSString *sourceFilePath = [NSString stringWithFormat:@"%@/%@.m", dataPath, name]; + NSData *dataToWrite = [codeStringHeader dataUsingEncoding:NSUTF8StringEncoding]; + + BOOL successCreate = [[NSFileManager defaultManager] createFileAtPath:headerFilePath contents:dataToWrite attributes:nil]; + dataToWrite = [codeStringSource dataUsingEncoding:NSUTF8StringEncoding]; + successCreate = successCreate && [[NSFileManager defaultManager] createFileAtPath:sourceFilePath contents:dataToWrite attributes:nil]; + + NSString *codeMapStringHeader = [self generateMappingSourceCodeWith:data name:name type:0 isTestData:isTest]; + NSString *codeMapStringSource = [self generateMappingSourceCodeWith:data name:name type:1 isTestData:isTest]; + NSString *headerMapFilePath = [NSString stringWithFormat:@"%@/%@Mapper.h", dataPath, name]; + NSString *sourceMapFilePath = [NSString stringWithFormat:@"%@/%@Mapper.m", dataPath, name]; + NSData *mapToWrite = [codeMapStringHeader dataUsingEncoding:NSUTF8StringEncoding]; + + BOOL successMapCreate = [[NSFileManager defaultManager] createFileAtPath:headerMapFilePath contents:mapToWrite attributes:nil]; + mapToWrite = [codeMapStringSource dataUsingEncoding:NSUTF8StringEncoding]; + successMapCreate = successMapCreate && [[NSFileManager defaultManager] createFileAtPath:sourceMapFilePath contents:mapToWrite attributes:nil]; + + NSLog(@"Create [%@] file to...\n%@", successCreate && successMapCreate?@"success":@"fail", dataPath); +} + +- (NSDictionary *)mappingObject:(NSDictionary *)parsedJSONData { + NSMutableDictionary *resMedata = [[NSMutableDictionary alloc] init]; + NSDictionary *countryCodeToRegionCodeMap = [parsedJSONData objectForKey:@"countryCodeToRegionCodeMap"]; + NSDictionary *countryToMetadata = [parsedJSONData objectForKey:@"countryToMetadata"]; + NSLog(@"- countryCodeToRegionCodeMap count [%zu]", (unsigned long)[countryCodeToRegionCodeMap count]); + NSLog(@"- countryToMetadata count [%zu]", (unsigned long)[countryToMetadata count]); + + [resMedata setObject:countryCodeToRegionCodeMap forKey:@"countryCodeToRegionCodeMap"]; + [resMedata setObject:countryToMetadata forKey:@"countryToMetadata"]; + + return resMedata; +} + + +- (NSString *)genRandStringLength:(int)len +{ + NSMutableString *randomString = [NSMutableString stringWithCapacity: len]; + + for (int i=0; i\n"]; + [contents appendString:@"#import \"NBPhoneMetaData.h\"\n\n"]; + + for (NSString *key in allKeys) { + NSString *className = [NSString stringWithFormat:@"%@%@", classPrefix, key]; + [contents appendFormat:@"@interface %@ : NBPhoneMetaData\n", className]; + [contents appendString:@"@end\n\n"]; + } + + } else if (type == 1) { + NSArray *allKeys = metadata.allKeys; + + [contents appendFormat:@"#import \"%@.h\"\n", name]; + [contents appendString:@"#import \"NBPhoneNumberDefines.h\"\n"]; + [contents appendString:@"#import \"NBPhoneNumberDesc.h\"\n\n"]; + [contents appendString:@"#import \"NBNumberFormat.h\"\n\n"]; + + for (NSString *key in allKeys) { + NSArray *currentMetadata = [metadata objectForKey:key]; + NSString *className = [NSString stringWithFormat:@"%@%@", classPrefix, key]; + [contents appendFormat:@"@implementation %@\n", className]; + [contents appendString:@"- (id)init\n"]; + [contents appendString:@"{\n"]; + [contents appendString:@" self = [super init];\n"]; + [contents appendString:@" if (self) {\n"]; + + /* 1 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:1] name:@"self.generalDesc"]]; + /* 2 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:2] name:@"self.fixedLine"]]; + /* 3 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:3] name:@"self.mobile"]]; + /* 4 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:4] name:@"self.tollFree"]]; + /* 5 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:5] name:@"self.premiumRate"]]; + /* 6 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:6] name:@"self.sharedCost"]]; + /* 7 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:7] name:@"self.personalNumber"]]; + /* 8 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:8] name:@"self.voip"]]; + + /* 21 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:21] name:@"self.pager"]]; + /* 25 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:25] name:@"self.uan"]]; + /* 27 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:27] name:@"self.emergency"]]; + /* 28 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:28] name:@"self.voicemail"]]; + /* 24 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:24] name:@"self.noInternationalDialling"]]; + /* 9 */ [contents appendFormat:@" self.codeID = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:9])]; + /* 10 */ [contents appendFormat:@" self.countryCode = %@;\n", NUM_VAL([currentMetadata safeObjectAtIndex:10])]; + /* 11 */ [contents appendFormat:@" self.internationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:11])]; + /* 17 */ [contents appendFormat:@" self.preferredInternationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:17])]; + /* 12 */ [contents appendFormat:@" self.nationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:12])]; + /* 13 */ [contents appendFormat:@" self.preferredExtnPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:13])]; + /* 15 */ [contents appendFormat:@" self.nationalPrefixForParsing = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:15])]; + /* 16 */ [contents appendFormat:@" self.nationalPrefixTransformRule = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:16])]; + /* 18 */ [contents appendFormat:@" self.sameMobileAndFixedLinePattern = %@;\n", [[currentMetadata safeObjectAtIndex:18] boolValue] ? @"YES":@"NO"]; + /* 19 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata safeObjectAtIndex:19] name:@"self.numberFormats"]]; // NBNumberFormat array + /* 20 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata safeObjectAtIndex:20] name:@"self.intlNumberFormats"]]; // NBNumberFormat array + /* 22 */ [contents appendFormat:@" self.mainCountryForCode = %@;\n", [[currentMetadata safeObjectAtIndex:22] boolValue] ? @"YES":@"NO"]; + /* 23 */ [contents appendFormat:@" self.leadingDigits = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:23])]; + /* 26 */ [contents appendFormat:@" self.leadingZeroPossible = %@;\n", [[currentMetadata safeObjectAtIndex:26] boolValue] ? @"YES":@"NO"]; + + [contents appendString:@" }\n"]; + [contents appendString:@" return self;\n"]; + [contents appendString:@"}\n"]; + + [contents appendString:@"@end\n\n"]; + } + } + + return contents; +} + + +- (NSString *)generateMappingSourceCodeWith:(NSDictionary*)data name:(NSString*)name type:(int)type isTestData:(BOOL)isTest +{ + NSMutableString *contents = [[NSMutableString alloc] init]; + + NSDictionary *mapCN2CCode = [data objectForKey:@"countryCodeToRegionCodeMap"]; + NSArray *allCallingCodeKey = mapCN2CCode.allKeys; + + [contents appendString:@"// DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator)\n\n"]; + + if (type == 0) { + [contents appendString:@"#import \n\n"]; + [contents appendFormat:@"@interface %@Mapper : NSObject\n\n", name]; + [contents appendString:@"+ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key;\n\n"]; + [contents appendString:@"@end\n\n"]; + } else if (type == 1) { + [contents appendFormat:@"#import \"%@Mapper.h\"\n\n", name]; + + [contents appendFormat:@"@implementation %@Mapper\n\n", name]; + [contents appendString:@"static NSMutableDictionary *kMapCCode2CN;\n\n"]; + [contents appendString:@"+ (NSArray *)ISOCodeFromCallingNumber:(NSString *)key\n"]; + [contents appendString:@"{\n"]; + [contents appendString:@" static dispatch_once_t onceToken;\n"]; + [contents appendString:@" dispatch_once(&onceToken, ^{\n"]; + [contents appendString:@" kMapCCode2CN = [[NSMutableDictionary alloc] init];\n"]; + + for (NSString *callingKey in allCallingCodeKey) { + NSArray *countryCodeArray = [mapCN2CCode objectForKey:callingKey]; + [contents appendString:@"\n"]; + [contents appendFormat:@" NSMutableArray *countryCode%@Array = [[NSMutableArray alloc] init];\n", callingKey]; + for (NSString *code in countryCodeArray) { + [contents appendFormat:@" [countryCode%@Array addObject:%@];\n", callingKey, STR_VAL(code)]; + } + [contents appendFormat:@" [kMapCCode2CN setObject:countryCode%@Array forKey:%@];\n", callingKey, STR_VAL(callingKey)]; + } + [contents appendString:@" });\n"]; + [contents appendString:@" return [kMapCCode2CN objectForKey:key];\n"]; + [contents appendString:@"}\n\n"]; + [contents appendString:@"@end\n\n"]; + } + + return contents; +} + + +- (NSString *)stringForSourceCode:(id)value +{ + if (value && [value isKindOfClass:[NSString class]]) { + value = [value stringByReplacingOccurrencesOfString:@"\\d" withString:@"\\\\d"]; + return [NSString stringWithFormat:@"@\"%@\"", value]; + } + + return @"nil"; +} + + +- (NSString *)numberForSourceCode:(id)value +{ + if (value && [value isKindOfClass:[NSNumber class]]) { + return [NSString stringWithFormat:@"[NSNumber numberWithInteger:%@]", value]; + } + return @"nil"; +} + + +- (NSString *)phoneNumberDescWithData:(id)value name:(NSString *)varName +{ + NSMutableString *contents = [[NSMutableString alloc] init]; + + NSString *initSentance = [self phoneNumberDescWithData:value]; + [contents appendFormat:@" %@ = %@;\n", varName, initSentance]; + return contents; +} + + +- (NSString *)phoneNumberDescWithData:(id)value +{ + NSString *initSentance = [NSString stringWithFormat:@"[[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:%@ withPossibleNumberPattern:%@ withExample:%@]", + STR_VAL([value safeObjectAtIndex:2]), STR_VAL([value safeObjectAtIndex:3]), STR_VAL([value safeObjectAtIndex:6])]; + return initSentance; +} + + +- (NSString *)phoneNumberFormatWithData:(id)value name:(NSString *)varName +{ + NSMutableString *contents = [[NSMutableString alloc] init]; + + NSString *cleanName = [[varName stringByReplacingOccurrencesOfString:@"." withString:@""] stringByReplacingOccurrencesOfString:@"self" withString:@""]; + NSString *arrayName = [NSString stringWithFormat:@"%@_patternArray", cleanName]; + + if (value != nil && [value isKindOfClass:[NSArray class]]) { + /* 1 */ NSString *pattern = [value safeObjectAtIndex:1]; + /* 2 */ NSString *format = [value safeObjectAtIndex:2]; + /* 4 */ NSString *nationalPrefixFormattingRule = [value safeObjectAtIndex:4]; + /* 6 */ BOOL nationalPrefixOptionalWhenFormatting = [[value safeObjectAtIndex:6] boolValue]; + /* 5 */ NSString *domesticCarrierCodeFormattingRule = [value safeObjectAtIndex:5]; + + [contents appendFormat:@"\n NSMutableArray *%@ = [[NSMutableArray alloc] init];\n", arrayName]; + + /* 3 */ id tmpData = [value safeObjectAtIndex:3]; + + if (tmpData != nil && [tmpData isKindOfClass:[NSArray class]]) { + for (id numFormat in tmpData) { + if ([numFormat isKindOfClass:[NSString class]]) { + [contents appendFormat:@" [%@ addObject:%@];\n", arrayName, STR_VAL(numFormat)]; + } else { + [contents appendFormat:@" [%@ addObject:%@];\n", arrayName, STR_VAL([numFormat stringValue])]; + } + } + } + + NSString *initSentance = [NSString stringWithFormat:@" NBNumberFormat *%@ = [[NBNumberFormat alloc] initWithPattern:%@ withFormat:%@ withLeadingDigitsPatterns:%@ withNationalPrefixFormattingRule:%@ whenFormatting:%@ withDomesticCarrierCodeFormattingRule:%@];\n", + varName, STR_VAL(pattern), STR_VAL(format), arrayName, STR_VAL(nationalPrefixFormattingRule), + nationalPrefixOptionalWhenFormatting ? @"YES":@"NO", STR_VAL(domesticCarrierCodeFormattingRule)]; + + [contents appendString:initSentance]; + } + + return contents; +} + + +- (NSString *)phoneNumberFormatArrayWithData:(id)value name:(NSString *)varName +{ + NSMutableString *contents = [[NSMutableString alloc] init]; + + NSString *cleanName = [[varName stringByReplacingOccurrencesOfString:@"." withString:@""] stringByReplacingOccurrencesOfString:@"self" withString:@""]; + NSString *arrayName = [NSString stringWithFormat:@"%@_FormatArray", cleanName]; + + [contents appendFormat:@"\n NSMutableArray *%@ = [[NSMutableArray alloc] init];\n", arrayName]; + + NSInteger index = 0; + + for (id data in value) { + NSString *tmpVarName = [NSString stringWithFormat:@"%@%@", cleanName, @(index++)]; + NSString *initSentance = [self phoneNumberFormatWithData:data name:tmpVarName]; + [contents appendString:initSentance]; + [contents appendFormat:@" [%@ addObject:%@];\n", arrayName, tmpVarName]; + } + + [contents appendFormat:@" %@ = %@;\n", varName, arrayName]; + return contents; +} + + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.h new file mode 100755 index 0000000000..7b95671e53 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.h @@ -0,0 +1,25 @@ +// +// NBPhoneNumber.h +// libPhoneNumber +// +// + +#import +#import "NBPhoneNumberDefines.h" + + +@interface NBPhoneNumber : NSObject + +// from phonemetadata.pb.js +/* 1 */ @property (nonatomic, strong, readwrite) NSNumber *countryCode; +/* 2 */ @property (nonatomic, strong, readwrite) NSNumber *nationalNumber; +/* 3 */ @property (nonatomic, strong, readwrite) NSString *extension; +/* 4 */ @property (nonatomic, assign, readwrite) BOOL italianLeadingZero; +/* 5 */ @property (nonatomic, strong, readwrite) NSString *rawInput; +/* 6 */ @property (nonatomic, strong, readwrite) NSNumber *countryCodeSource; +/* 7 */ @property (nonatomic, strong, readwrite) NSString *preferredDomesticCarrierCode; + +- (void)clearCountryCodeSource; +- (NBECountryCodeSource)getCountryCodeSourceOrDefault; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.m new file mode 100755 index 0000000000..919d0fa972 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumber.m @@ -0,0 +1,119 @@ +// +// NBPhoneNumber.m +// libPhoneNumber +// +// + +#import "NBPhoneNumber.h" +#import "NBPhoneNumberDefines.h" + + +@implementation NBPhoneNumber + +- (id)init +{ + self = [super init]; + + if (self) { + self.countryCodeSource = nil; + self.italianLeadingZero = NO; + self.nationalNumber = @-1; + self.countryCode = @-1; + } + + return self; +} + + +- (void)clearCountryCodeSource +{ + [self setCountryCodeSource:nil]; +} + + +- (NBECountryCodeSource)getCountryCodeSourceOrDefault +{ + if (!self.countryCodeSource) { + return NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN; + } + + return [self.countryCodeSource integerValue]; +} + + +- (BOOL)isEqualToObject:(NBPhoneNumber*)otherObj +{ + return [self isEqual:otherObj]; +} + + +- (NSUInteger)hash +{ + NSData *selfObject = [NSKeyedArchiver archivedDataWithRootObject:self]; + return [selfObject hash]; +} + + +- (BOOL)isEqual:(id)object +{ + if (![object isKindOfClass:[NBPhoneNumber class]]) { + return NO; + } + + NBPhoneNumber *other = object; + return ([self.countryCode isEqualToNumber:other.countryCode]) && ([self.nationalNumber isEqualToNumber:other.nationalNumber]) && + (self.italianLeadingZero == other.italianLeadingZero) && + ((self.extension == nil && other.extension == nil) || [self.extension isEqualToString:other.extension]); +} + + +- (id)copyWithZone:(NSZone *)zone +{ + NBPhoneNumber *phoneNumberCopy = [[NBPhoneNumber allocWithZone:zone] init]; + + phoneNumberCopy.countryCode = [self.countryCode copy]; + phoneNumberCopy.nationalNumber = [self.nationalNumber copy]; + phoneNumberCopy.extension = [self.extension copy]; + phoneNumberCopy.italianLeadingZero = self.italianLeadingZero; + phoneNumberCopy.rawInput = [self.rawInput copy]; + phoneNumberCopy.countryCodeSource = [self.countryCodeSource copy]; + phoneNumberCopy.preferredDomesticCarrierCode = [self.preferredDomesticCarrierCode copy]; + + return phoneNumberCopy; +} + + +- (id)initWithCoder:(NSCoder*)coder +{ + if (self = [super init]) { + self.countryCode = [coder decodeObjectForKey:@"countryCode"]; + self.nationalNumber = [coder decodeObjectForKey:@"nationalNumber"]; + self.extension = [coder decodeObjectForKey:@"extension"]; + self.italianLeadingZero = [[coder decodeObjectForKey:@"italianLeadingZero"] boolValue]; + self.rawInput = [coder decodeObjectForKey:@"rawInput"]; + self.countryCodeSource = [coder decodeObjectForKey:@"countryCodeSource"]; + self.preferredDomesticCarrierCode = [coder decodeObjectForKey:@"preferredDomesticCarrierCode"]; + } + return self; +} + + +- (void)encodeWithCoder:(NSCoder*)coder +{ + [coder encodeObject:self.countryCode forKey:@"countryCode"]; + [coder encodeObject:self.nationalNumber forKey:@"nationalNumber"]; + [coder encodeObject:self.extension forKey:@"extension"]; + [coder encodeObject:[NSNumber numberWithBool:self.italianLeadingZero] forKey:@"italianLeadingZero"]; + [coder encodeObject:self.rawInput forKey:@"rawInput"]; + [coder encodeObject:self.countryCodeSource forKey:@"countryCodeSource"]; + [coder encodeObject:self.preferredDomesticCarrierCode forKey:@"preferredDomesticCarrierCode"]; +} + + + +- (NSString *)description +{ + return [NSString stringWithFormat:@" - countryCode[%@], nationalNumber[%@], extension[%@], italianLeadingZero[%@], rawInput[%@] countryCodeSource[%@] preferredDomesticCarrierCode[%@]", self.countryCode, self.nationalNumber, self.extension, self.italianLeadingZero?@"Y":@"N", self.rawInput, self.countryCodeSource, self.preferredDomesticCarrierCode]; +} + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.h new file mode 100755 index 0000000000..32886de97f --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.h @@ -0,0 +1,88 @@ +// +// NBPhoneNumberDefines.h +// libPhoneNumber +// +// + +#import + +#ifndef libPhoneNumber_NBPhoneNumberDefines_h +#define libPhoneNumber_NBPhoneNumberDefines_h + +#define NB_YES [NSNumber numberWithBool:YES] +#define NB_NO [NSNumber numberWithBool:NO] + +#pragma mark - Enum - + +typedef NS_ENUM(NSInteger, NBEPhoneNumberFormat) { + NBEPhoneNumberFormatE164 = 0, + NBEPhoneNumberFormatINTERNATIONAL = 1, + NBEPhoneNumberFormatNATIONAL = 2, + NBEPhoneNumberFormatRFC3966 = 3 +}; + + +typedef NS_ENUM(NSInteger, NBEPhoneNumberType) { + NBEPhoneNumberTypeFIXED_LINE = 0, + NBEPhoneNumberTypeMOBILE = 1, + // In some regions (e.g. the USA), it is impossible to distinguish between + // fixed-line and mobile numbers by looking at the phone number itself. + NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE = 2, + // Freephone lines + NBEPhoneNumberTypeTOLL_FREE = 3, + NBEPhoneNumberTypePREMIUM_RATE = 4, + // The cost of this call is shared between the caller and the recipient, and + // is hence typically less than PREMIUM_RATE calls. See + // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information. + NBEPhoneNumberTypeSHARED_COST = 5, + // Voice over IP numbers. This includes TSoIP (Telephony Service over IP). + NBEPhoneNumberTypeVOIP = 6, + // A personal number is associated with a particular person, and may be routed + // to either a MOBILE or FIXED_LINE number. Some more information can be found + // here = http://en.wikipedia.org/wiki/Personal_Numbers + NBEPhoneNumberTypePERSONAL_NUMBER = 7, + NBEPhoneNumberTypePAGER = 8, + // Used for 'Universal Access Numbers' or 'Company Numbers'. They may be + // further routed to specific offices, but allow one number to be used for a + // company. + NBEPhoneNumberTypeUAN = 9, + // Used for 'Voice Mail Access Numbers'. + NBEPhoneNumberTypeVOICEMAIL = 10, + // A phone number is of type UNKNOWN when it does not fit any of the known + // patterns for a specific region. + NBEPhoneNumberTypeUNKNOWN = -1 +}; + + +typedef NS_ENUM(NSInteger, NBEMatchType) { + NBEMatchTypeNOT_A_NUMBER = 0, + NBEMatchTypeNO_MATCH = 1, + NBEMatchTypeSHORT_NSN_MATCH = 2, + NBEMatchTypeNSN_MATCH = 3, + NBEMatchTypeEXACT_MATCH = 4 +}; + + +typedef NS_ENUM(NSInteger, NBEValidationResult) { + NBEValidationResultUNKNOWN = 0, + NBEValidationResultIS_POSSIBLE = 1, + NBEValidationResultINVALID_COUNTRY_CODE = 2, + NBEValidationResultTOO_SHORT = 3, + NBEValidationResultTOO_LONG = 4 +}; + + +typedef NS_ENUM(NSInteger, NBECountryCodeSource) { + NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN = 1, + NBECountryCodeSourceFROM_NUMBER_WITH_IDD = 5, + NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN = 10, + NBECountryCodeSourceFROM_DEFAULT_COUNTRY = 20 +}; + +extern NSString * const NB_UNKNOWN_REGION; +extern NSString * const NB_NON_BREAKING_SPACE; +extern NSString * const NB_PLUS_CHARS; +extern NSString * const NB_VALID_DIGITS_STRING; +extern NSString * const NB_REGION_CODE_FOR_NON_GEO_ENTITY; + +#endif diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.m new file mode 100644 index 0000000000..e0a3f17299 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDefines.m @@ -0,0 +1,7 @@ +#import "NBPhoneNumberDefines.h" + +NSString * const NB_UNKNOWN_REGION = @"ZZ"; +NSString * const NB_NON_BREAKING_SPACE = @"\u00a0"; +NSString * const NB_PLUS_CHARS = @"++"; +NSString * const NB_VALID_DIGITS_STRING = @"0-90-9٠-٩۰-۹"; +NSString * const NB_REGION_CODE_FOR_NON_GEO_ENTITY = @"001"; diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.h new file mode 100755 index 0000000000..37111a7784 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.h @@ -0,0 +1,19 @@ +// +// NBPhoneNumberDesc.h +// libPhoneNumber +// +// + +#import + + +@interface NBPhoneNumberDesc : NSObject + +// from phonemetadata.pb.js +/* 2 */ @property (nonatomic, strong, readwrite) NSString *nationalNumberPattern; +/* 3 */ @property (nonatomic, strong, readwrite) NSString *possibleNumberPattern; +/* 6 */ @property (nonatomic, strong, readwrite) NSString *exampleNumber; + +- (id)initWithNationalNumberPattern:(NSString *)nnp withPossibleNumberPattern:(NSString *)pnp withExample:(NSString *)exp; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.m new file mode 100755 index 0000000000..731cde861c --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberDesc.m @@ -0,0 +1,121 @@ +// +// NBPhoneNumberDesc.m +// libPhoneNumber +// +// + +#import "NBPhoneNumberDesc.h" + +@interface NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index; +@end + +@implementation NSArray (NBAdditions) +- (id)safeObjectAtIndex:(NSUInteger)index { + @synchronized(self) { + if (index >= [self count]) return nil; + id res = [self objectAtIndex:index]; + if (res == nil || (NSNull*)res == [NSNull null]) { + return nil; + } + return res; + } +} +@end + + +@implementation NBPhoneNumberDesc + +- (id)initWithData:(id)data +{ + NSString *nnp = nil; + NSString *pnp = nil; + NSString *exp = nil; + + if (data != nil && [data isKindOfClass:[NSArray class]]) { + /* 2 */ nnp = [data safeObjectAtIndex:2]; + /* 3 */ pnp = [data safeObjectAtIndex:3]; + /* 6 */ exp = [data safeObjectAtIndex:6]; + } + + return [self initWithNationalNumberPattern:nnp withPossibleNumberPattern:pnp withExample:exp]; +} + + +- (id)initWithNationalNumberPattern:(NSString *)nnp withPossibleNumberPattern:(NSString *)pnp withExample:(NSString *)exp +{ + self = [self init]; + + if (self) { + self.nationalNumberPattern = nnp; + self.possibleNumberPattern = pnp; + self.exampleNumber = exp; + } + + return self; + +} + + +- (id)init +{ + self = [super init]; + + if (self) { + } + + return self; +} + + +- (id)initWithCoder:(NSCoder*)coder +{ + if (self = [super init]) { + self.nationalNumberPattern = [coder decodeObjectForKey:@"nationalNumberPattern"]; + self.possibleNumberPattern = [coder decodeObjectForKey:@"possibleNumberPattern"]; + self.exampleNumber = [coder decodeObjectForKey:@"exampleNumber"]; + } + return self; +} + + +- (void)encodeWithCoder:(NSCoder*)coder +{ + [coder encodeObject:self.nationalNumberPattern forKey:@"nationalNumberPattern"]; + [coder encodeObject:self.possibleNumberPattern forKey:@"possibleNumberPattern"]; + [coder encodeObject:self.exampleNumber forKey:@"exampleNumber"]; +} + + +- (NSString *)description +{ + return [NSString stringWithFormat:@"nationalNumberPattern[%@] possibleNumberPattern[%@] exampleNumber[%@]", + self.nationalNumberPattern, self.possibleNumberPattern, self.exampleNumber]; +} + + +- (id)copyWithZone:(NSZone *)zone +{ + NBPhoneNumberDesc *phoneDescCopy = [[NBPhoneNumberDesc allocWithZone:zone] init]; + + phoneDescCopy.nationalNumberPattern = [self.nationalNumberPattern copy]; + phoneDescCopy.possibleNumberPattern = [self.possibleNumberPattern copy]; + phoneDescCopy.exampleNumber = [self.exampleNumber copy]; + + return phoneDescCopy; +} + + +- (BOOL)isEqual:(id)object +{ + if ([object isKindOfClass:[NBPhoneNumberDesc class]] == NO) { + return NO; + } + + NBPhoneNumberDesc *other = object; + return [self.nationalNumberPattern isEqual:other.nationalNumberPattern] && + [self.possibleNumberPattern isEqual:other.possibleNumberPattern] && + [self.exampleNumber isEqual:other.exampleNumber]; +} + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.h b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.h new file mode 100755 index 0000000000..428439b7e6 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.h @@ -0,0 +1,103 @@ +// +// NBPhoneNumberUtil.h +// libPhoneNumber +// +// Created by tabby on 2015. 2. 8.. +// Copyright (c) 2015년 ohtalk.me. All rights reserved. +// + +#import +#import "NBPhoneNumberDefines.h" + + +@class NBPhoneMetaData, NBPhoneNumber; + +@interface NBPhoneNumberUtil : NSObject + ++ (NBPhoneNumberUtil*)sharedInstance; + +// regular expressions +- (NSArray*)matchesByRegex:(NSString*)sourceString regex:(NSString*)pattern; +- (NSArray*)matchedStringByRegex:(NSString*)sourceString regex:(NSString*)pattern; +- (NSString*)replaceStringByRegex:(NSString*)sourceString regex:(NSString*)pattern withTemplate:(NSString*)templateString; +- (int)stringPositionByRegex:(NSString*)sourceString regex:(NSString*)pattern; + +// libPhoneNumber Util functions +- (NSString*)convertAlphaCharactersInNumber:(NSString*)number; + +- (NSString*)normalizePhoneNumber:(NSString*)phoneNumber; +- (NSString*)normalizeDigitsOnly:(NSString*)number; + +- (BOOL)isNumberGeographical:(NBPhoneNumber*)phoneNumber; + +- (NSString*)extractPossibleNumber:(NSString*)phoneNumber; +- (NSNumber*)extractCountryCode:(NSString*)fullNumber nationalNumber:(NSString**)nationalNumber; +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH +- (NSString *)countryCodeByCarrier; +#endif + +- (NSString*)getNddPrefixForRegion:(NSString*)regionCode stripNonDigits:(BOOL)stripNonDigits; +- (NSString*)getNationalSignificantNumber:(NBPhoneNumber*)phoneNumber; + +- (NSArray *)getSupportedRegions; + +- (NBEPhoneNumberType)getNumberType:(NBPhoneNumber*)phoneNumber; + +- (NSNumber*)getCountryCodeForRegion:(NSString*)regionCode; + +- (NSString*)getRegionCodeForCountryCode:(NSNumber*)countryCallingCode; +- (NSArray*)getRegionCodesForCountryCode:(NSNumber*)countryCallingCode; +- (NSString*)getRegionCodeForNumber:(NBPhoneNumber*)phoneNumber; + +- (NBPhoneNumber*)getExampleNumber:(NSString*)regionCode error:(NSError**)error; +- (NBPhoneNumber*)getExampleNumberForType:(NSString*)regionCode type:(NBEPhoneNumberType)type error:(NSError**)error; +- (NBPhoneNumber*)getExampleNumberForNonGeoEntity:(NSNumber*)countryCallingCode error:(NSError**)error; + +- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number error:(NSError**)error; + +- (BOOL)truncateTooLongNumber:(NBPhoneNumber*)number; + +- (BOOL)isValidNumber:(NBPhoneNumber*)number; +- (BOOL)isViablePhoneNumber:(NSString*)phoneNumber; +- (BOOL)isAlphaNumber:(NSString*)number; +- (BOOL)isValidNumberForRegion:(NBPhoneNumber*)number regionCode:(NSString*)regionCode; +- (BOOL)isNANPACountry:(NSString*)regionCode; +- (BOOL)isLeadingZeroPossible:(NSNumber*)countryCallingCode; + +- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number error:(NSError**)error; + +- (BOOL)isPossibleNumber:(NBPhoneNumber*)number; +- (BOOL)isPossibleNumber:(NBPhoneNumber*)number error:(NSError**)error; +- (BOOL)isPossibleNumberString:(NSString*)number regionDialingFrom:(NSString*)regionDialingFrom error:(NSError**)error; + +- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn error:(NSError**)error; + +- (int)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber error:(NSError**)error; +- (int)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber error:(NSError**)error; + +- (BOOL)maybeStripNationalPrefixAndCarrierCode:(NSString**)numberStr metadata:(NBPhoneMetaData*)metadata carrierCode:(NSString**)carrierCode; +- (NBECountryCodeSource)maybeStripInternationalPrefixAndNormalize:(NSString**)numberStr possibleIddPrefix:(NSString*)possibleIddPrefix; + +- (NSNumber*)maybeExtractCountryCode:(NSString*)number metadata:(NBPhoneMetaData*)defaultRegionMetadata + nationalNumber:(NSString**)nationalNumber keepRawInput:(BOOL)keepRawInput + phoneNumber:(NBPhoneNumber**)phoneNumber error:(NSError**)error; + +- (NBPhoneNumber*)parse:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error; +- (NBPhoneNumber*)parseAndKeepRawInput:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error; +- (NBPhoneNumber*)parseWithPhoneCarrierRegion:(NSString*)numberToParse error:(NSError**)error; + +- (NSString*)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat error:(NSError**)error; +- (NSString*)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats error:(NSError**)error; +- (NSString*)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom withFormatting:(BOOL)withFormatting error:(NSError**)error; +- (NSString*)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error; +- (NSString*)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error; +- (NSString*)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString*)carrierCode error:(NSError**)error; +- (NSString*)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error; +- (NSString*)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number fallbackCarrierCode:(NSString*)fallbackCarrierCode error:(NSError**)error; + +- (BOOL)formattingRuleHasFirstGroupOnly:(NSString*)nationalPrefixFormattingRule; + +@property (nonatomic, strong, readonly) NSDictionary *DIGIT_MAPPINGS; +@property (nonatomic, strong, readonly) NSBundle *libPhoneBundle; + +@end diff --git a/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m new file mode 100755 index 0000000000..282ca96cd1 --- /dev/null +++ b/submodules/TelegramCore/third-party/libphonenumber-iOS/NBPhoneNumberUtil.m @@ -0,0 +1,3907 @@ +// +// NBPhoneNumberUtil.m +// libPhoneNumber +// +// Created by tabby on 2015. 2. 8.. +// Copyright (c) 2015년 ohtalk.me. All rights reserved. +// + +#import "NBPhoneNumberUtil.h" +#import "NBPhoneNumberDefines.h" +#import "NBPhoneNumber.h" +#import "NBNumberFormat.h" +#import "NBPhoneNumberDesc.h" +#import "NBPhoneMetaData.h" +#import "NBMetadataHelper.h" +#import + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH +#import +#import +#endif + + +#pragma mark - NBPhoneNumberUtil interface - + +@interface NBPhoneNumberUtil () + +@property (nonatomic, strong) NSLock *entireStringCacheLock; +@property (nonatomic, strong) NSMutableDictionary *entireStringRegexCache; + +@property (nonatomic, strong) NSLock *lockPatternCache; +@property (nonatomic, strong) NSMutableDictionary *regexPatternCache; + +@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nNumberFormat; +@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nPhoneNumberDesc; +@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nPhoneMetadata; + +@property (nonatomic, strong) NSRegularExpression *PLUS_CHARS_PATTERN; +@property (nonatomic, strong) NSRegularExpression *CAPTURING_DIGIT_PATTERN; +@property (nonatomic, strong) NSRegularExpression *VALID_ALPHA_PHONE_PATTERN; + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH +@property (nonatomic, readonly) CTTelephonyNetworkInfo *telephonyNetworkInfo; +#endif + +@end + + +@implementation NBPhoneNumberUtil + +#pragma mark - Static Int variables - +const static NSUInteger NANPA_COUNTRY_CODE_ = 1; +const static int MIN_LENGTH_FOR_NSN_ = 2; +const static int MAX_LENGTH_FOR_NSN_ = 16; +const static int MAX_LENGTH_COUNTRY_CODE_ = 3; +const static int MAX_INPUT_STRING_LENGTH_ = 250; + +#pragma mark - Static String variables - +static NSString *VALID_PUNCTUATION = @"-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~"; + +static NSString *INVALID_COUNTRY_CODE_STR = @"Invalid country calling code"; +static NSString *NOT_A_NUMBER_STR = @"The string supplied did not seem to be a phone number"; +static NSString *TOO_SHORT_AFTER_IDD_STR = @"Phone number too short after IDD"; +static NSString *TOO_SHORT_NSN_STR = @"The string supplied is too short to be a phone number"; +static NSString *TOO_LONG_STR = @"The string supplied is too long to be a phone number"; + +static NSString *COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = @"3"; +static NSString *PLUS_SIGN = @"+"; +static NSString *STAR_SIGN = @"*"; +static NSString *RFC3966_EXTN_PREFIX = @";ext="; +static NSString *RFC3966_PREFIX = @"tel:"; +static NSString *RFC3966_PHONE_CONTEXT = @";phone-context="; +static NSString *RFC3966_ISDN_SUBADDRESS = @";isub="; +static NSString *DEFAULT_EXTN_PREFIX = @" ext. "; +static NSString *VALID_ALPHA = @"A-Za-z"; + +#pragma mark - Static regular expression strings - +static NSString *NON_DIGITS_PATTERN = @"\\D+"; +static NSString *CC_PATTERN = @"\\$CC"; +static NSString *FIRST_GROUP_PATTERN = @"(\\$\\d)"; +static NSString *FIRST_GROUP_ONLY_PREFIX_PATTERN = @"^\\(?\\$1\\)?"; +static NSString *NP_PATTERN = @"\\$NP"; +static NSString *FG_PATTERN = @"\\$FG"; +static NSString *VALID_ALPHA_PHONE_PATTERN_STRING = @"(?:.*?[A-Za-z]){3}.*"; + +static NSString *UNIQUE_INTERNATIONAL_PREFIX = @"[\\d]+(?:[~\\u2053\\u223C\\uFF5E][\\d]+)?"; + +static NSString *LEADING_PLUS_CHARS_PATTERN; +static NSString *EXTN_PATTERN; +static NSString *SEPARATOR_PATTERN; +static NSString *VALID_PHONE_NUMBER_PATTERN; +static NSString *VALID_START_CHAR_PATTERN; +static NSString *UNWANTED_END_CHAR_PATTERN; +static NSString *SECOND_NUMBER_START_PATTERN; + +static NSDictionary *ALPHA_MAPPINGS; +static NSDictionary *ALL_NORMALIZATION_MAPPINGS; +static NSDictionary *DIALLABLE_CHAR_MAPPINGS; +static NSDictionary *ALL_PLUS_NUMBER_GROUPING_SYMBOLS; + +static NSDictionary *DIGIT_MAPPINGS; + +static NSArray *GEO_MOBILE_COUNTRIES; + + +#pragma mark - Deprecated methods + ++ (NBPhoneNumberUtil *)sharedInstance +{ + static NBPhoneNumberUtil *sharedOnceInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ sharedOnceInstance = [[self alloc] init]; }); + return sharedOnceInstance; +} + + +#pragma mark - NSError + +- (NSError*)errorWithObject:(id)obj withDomain:(NSString *)domain +{ + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:obj forKey:NSLocalizedDescriptionKey]; + NSError *error = [NSError errorWithDomain:domain code:0 userInfo:userInfo]; + return error; +} + + +- (NSRegularExpression *)entireRegularExpressionWithPattern:(NSString *)regexPattern + options:(NSRegularExpressionOptions)options + error:(NSError **)error +{ + [_entireStringCacheLock lock]; + + @try { + if (!_entireStringRegexCache) { + _entireStringRegexCache = [[NSMutableDictionary alloc] init]; + } + + NSRegularExpression *regex = [_entireStringRegexCache objectForKey:regexPattern]; + if (! regex) + { + NSString *finalRegexString = regexPattern; + if ([regexPattern rangeOfString:@"^"].location == NSNotFound) { + finalRegexString = [NSString stringWithFormat:@"^(?:%@)$", regexPattern]; + } + + regex = [self regularExpressionWithPattern:finalRegexString options:0 error:error]; + [_entireStringRegexCache setObject:regex forKey:regexPattern]; + } + + return regex; + } + @finally { + [_entireStringCacheLock unlock]; + } +} + + +- (NSRegularExpression *)regularExpressionWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError **)error +{ + [_lockPatternCache lock]; + + @try { + if (!_regexPatternCache) { + _regexPatternCache = [[NSMutableDictionary alloc] init]; + } + + NSRegularExpression *regex = [_regexPatternCache objectForKey:pattern]; + if (!regex) { + regex = [NSRegularExpression regularExpressionWithPattern:pattern options:options error:error]; + [_regexPatternCache setObject:regex forKey:pattern]; + } + return regex; + } + @finally { + [_lockPatternCache unlock]; + } +} + + +- (NSMutableArray*)componentsSeparatedByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + NSString *replacedString = [self replaceStringByRegex:sourceString regex:pattern withTemplate:@""]; + NSMutableArray *resArray = [[replacedString componentsSeparatedByString:@""] mutableCopy]; + [resArray removeObject:@""]; + return resArray; +} + + +- (int)stringPositionByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + if (sourceString == nil || sourceString.length <= 0 || pattern == nil || pattern.length <= 0) { + return -1; + } + + NSError *error = nil; + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + + int foundPosition = -1; + + if (matches.count > 0) { + NSTextCheckingResult *match = [matches objectAtIndex:0]; + return (int)match.range.location; + } + + return foundPosition; +} + + +- (int)indexOfStringByString:(NSString *)sourceString target:(NSString *)targetString +{ + NSRange finded = [sourceString rangeOfString:targetString]; + if (finded.location != NSNotFound) { + return (int)finded.location; + } + + return -1; +} + + +- (NSString *)replaceFirstStringByRegex:(NSString *)sourceString regex:(NSString *)pattern withTemplate:(NSString *)templateString +{ + NSString *replacementResult = [sourceString copy]; + NSError *error = nil; + + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSRange replaceRange = [currentPattern rangeOfFirstMatchInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + + if (replaceRange.location != NSNotFound) { + replacementResult = [currentPattern stringByReplacingMatchesInString:[sourceString mutableCopy] options:0 + range:replaceRange + withTemplate:templateString]; + } + + return replacementResult; +} + + +- (NSString *)replaceStringByRegex:(NSString *)sourceString regex:(NSString *)pattern withTemplate:(NSString *)templateString +{ + NSString *replacementResult = [sourceString copy]; + NSError *error = nil; + + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + + if ([matches count] == 1) { + NSRange replaceRange = [currentPattern rangeOfFirstMatchInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + + if (replaceRange.location != NSNotFound) { + replacementResult = [currentPattern stringByReplacingMatchesInString:[sourceString mutableCopy] options:0 + range:replaceRange + withTemplate:templateString]; + } + return replacementResult; + } + + if ([matches count] > 1) { + replacementResult = [currentPattern stringByReplacingMatchesInString:[replacementResult mutableCopy] options:0 + range:NSMakeRange(0, sourceString.length) withTemplate:templateString]; + return replacementResult; + } + + return replacementResult; +} + + +- (NSTextCheckingResult*)matcheFirstByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + NSError *error = nil; + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + if ([matches count] > 0) + return [matches objectAtIndex:0]; + return nil; +} + + +- (NSArray*)matchesByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + NSError *error = nil; + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + return matches; +} + + +- (NSArray*)matchedStringByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + NSArray *matches = [self matchesByRegex:sourceString regex:pattern]; + NSMutableArray *matchString = [[NSMutableArray alloc] init]; + + for (NSTextCheckingResult *match in matches) { + NSString *curString = [sourceString substringWithRange:match.range]; + [matchString addObject:curString]; + } + + return matchString; +} + + +- (BOOL)isStartingStringByRegex:(NSString *)sourceString regex:(NSString *)pattern +{ + NSError *error = nil; + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern options:0 error:&error]; + NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)]; + + for (NSTextCheckingResult *match in matches) { + if (match.range.location == 0) { + return YES; + } + } + + return NO; +} + + +- (NSString *)stringByReplacingOccurrencesString:(NSString *)sourceString withMap:(NSDictionary *)dicMap removeNonMatches:(BOOL)bRemove +{ + NSMutableString *targetString = [[NSMutableString alloc] initWithString:@""]; + + for(unsigned int i=0; i} + * @private + */ + // @[ Mexico, Argentina, Brazil ] + GEO_MOBILE_COUNTRIES = @[ @52, @54, @55 ]; + + [self initRegularExpressionSet]; + [self initNormalizationMappings]; + } + + return self; +} + + +- (void)initRegularExpressionSet +{ + NSString *EXTN_PATTERNS_FOR_PARSING = @"(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[ \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xxX##~~]|int|anexo|int)[:\\..]?[ \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)$"; + + NSError *error = nil; + + if (!_PLUS_CHARS_PATTERN) { + _PLUS_CHARS_PATTERN = [self regularExpressionWithPattern:[NSString stringWithFormat:@"[%@]+", NB_PLUS_CHARS] options:0 error:&error]; + } + + if (!LEADING_PLUS_CHARS_PATTERN) { + LEADING_PLUS_CHARS_PATTERN = [NSString stringWithFormat:@"^[%@]+", NB_PLUS_CHARS]; + } + + if (!_CAPTURING_DIGIT_PATTERN) { + _CAPTURING_DIGIT_PATTERN = [self regularExpressionWithPattern:[NSString stringWithFormat:@"([%@])", NB_VALID_DIGITS_STRING] options:0 error:&error]; + } + + if (!VALID_START_CHAR_PATTERN) { + VALID_START_CHAR_PATTERN = [NSString stringWithFormat:@"[%@%@]", NB_PLUS_CHARS, NB_VALID_DIGITS_STRING]; + } + + if (!SECOND_NUMBER_START_PATTERN) { + SECOND_NUMBER_START_PATTERN = @"[\\\\\\/] *x"; + } + + if (!_VALID_ALPHA_PHONE_PATTERN) { + _VALID_ALPHA_PHONE_PATTERN = [self regularExpressionWithPattern:VALID_ALPHA_PHONE_PATTERN_STRING options:0 error:&error]; + } + + if (!UNWANTED_END_CHAR_PATTERN) { + UNWANTED_END_CHAR_PATTERN = [NSString stringWithFormat:@"[^%@%@#]+$", NB_VALID_DIGITS_STRING, VALID_ALPHA]; + } + + if (!EXTN_PATTERN) { + EXTN_PATTERN = [NSString stringWithFormat:@"(?:%@)$", EXTN_PATTERNS_FOR_PARSING]; + } + + if (!SEPARATOR_PATTERN) { + SEPARATOR_PATTERN = [NSString stringWithFormat:@"[%@]+", VALID_PUNCTUATION]; + } + + if (!VALID_PHONE_NUMBER_PATTERN) { + VALID_PHONE_NUMBER_PATTERN = @"^[0-90-9٠-٩۰-۹]{2}$|^[++]*(?:[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~*]*[0-90-9٠-٩۰-۹]){3,}[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~*A-Za-z0-90-9٠-٩۰-۹]*(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[ \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xx##~~]|int|anexo|int)[:\\..]?[ \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)?$"; + } +} + +- (NSDictionary *)DIGIT_MAPPINGS +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + DIGIT_MAPPINGS = [NSDictionary dictionaryWithObjectsAndKeys: + @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9", + // Fullwidth digit 0 to 9 + @"0", @"\uFF10", @"1", @"\uFF11", @"2", @"\uFF12", @"3", @"\uFF13", @"4", @"\uFF14", @"5", @"\uFF15", @"6", @"\uFF16", @"7", @"\uFF17", @"8", @"\uFF18", @"9", @"\uFF19", + // Arabic-indic digit 0 to 9 + @"0", @"\u0660", @"1", @"\u0661", @"2", @"\u0662", @"3", @"\u0663", @"4", @"\u0664", @"5", @"\u0665", @"6", @"\u0666", @"7", @"\u0667", @"8", @"\u0668", @"9", @"\u0669", + // Eastern-Arabic digit 0 to 9 + @"0", @"\u06F0", @"1", @"\u06F1", @"2", @"\u06F2", @"3", @"\u06F3", @"4", @"\u06F4", @"5", @"\u06F5", @"6", @"\u06F6", @"7", @"\u06F7", @"8", @"\u06F8", @"9", @"\u06F9", nil]; + }); + return DIGIT_MAPPINGS; +} + + +- (void)initNormalizationMappings +{ + if (!DIALLABLE_CHAR_MAPPINGS) { + DIALLABLE_CHAR_MAPPINGS = [NSDictionary dictionaryWithObjectsAndKeys: + @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9", + @"+", @"+", @"*", @"*", nil]; + } + + if (!ALPHA_MAPPINGS) { + ALPHA_MAPPINGS = [NSDictionary dictionaryWithObjectsAndKeys: + @"2", @"A", @"2", @"B", @"2", @"C", @"3", @"D", @"3", @"E", @"3", @"F", @"4", @"G", @"4", @"H", @"4", @"I", @"5", @"J", + @"5", @"K", @"5", @"L", @"6", @"M", @"6", @"N", @"6", @"O", @"7", @"P", @"7", @"Q", @"7", @"R", @"7", @"S", @"8", @"T", + @"8", @"U", @"8", @"V", @"9", @"W", @"9", @"X", @"9", @"Y", @"9", @"Z", nil]; + } + + if (!ALL_NORMALIZATION_MAPPINGS) { + ALL_NORMALIZATION_MAPPINGS = [NSDictionary dictionaryWithObjectsAndKeys: + @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9", + // Fullwidth digit 0 to 9 + @"0", @"\uFF10", @"1", @"\uFF11", @"2", @"\uFF12", @"3", @"\uFF13", @"4", @"\uFF14", @"5", @"\uFF15", @"6", @"\uFF16", @"7", @"\uFF17", @"8", @"\uFF18", @"9", @"\uFF19", + // Arabic-indic digit 0 to 9 + @"0", @"\u0660", @"1", @"\u0661", @"2", @"\u0662", @"3", @"\u0663", @"4", @"\u0664", @"5", @"\u0665", @"6", @"\u0666", @"7", @"\u0667", @"8", @"\u0668", @"9", @"\u0669", + // Eastern-Arabic digit 0 to 9 + @"0", @"\u06F0", @"1", @"\u06F1", @"2", @"\u06F2", @"3", @"\u06F3", @"4", @"\u06F4", @"5", @"\u06F5", @"6", @"\u06F6", @"7", @"\u06F7", @"8", @"\u06F8", @"9", @"\u06F9", + @"2", @"A", @"2", @"B", @"2", @"C", @"3", @"D", @"3", @"E", @"3", @"F", @"4", @"G", @"4", @"H", @"4", @"I", @"5", @"J", + @"5", @"K", @"5", @"L", @"6", @"M", @"6", @"N", @"6", @"O", @"7", @"P", @"7", @"Q", @"7", @"R", @"7", @"S", @"8", @"T", + @"8", @"U", @"8", @"V", @"9", @"W", @"9", @"X", @"9", @"Y", @"9", @"Z", nil]; + } + + if (!ALL_PLUS_NUMBER_GROUPING_SYMBOLS) { + ALL_PLUS_NUMBER_GROUPING_SYMBOLS = [NSDictionary dictionaryWithObjectsAndKeys: + @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9", + @"A", @"A", @"B", @"B", @"C", @"C", @"D", @"D", @"E", @"E", @"F", @"F", @"G", @"G", @"H", @"H", @"I", @"I", @"J", @"J", + @"K", @"K", @"L", @"L", @"M", @"M", @"N", @"N", @"O", @"O", @"P", @"P", @"Q", @"Q", @"R", @"R", @"S", @"S", @"T", @"T", + @"U", @"U", @"V", @"V", @"W", @"W", @"X", @"X", @"Y", @"Y", @"Z", @"Z", @"A", @"a", @"B", @"b", @"C", @"c", @"D", @"d", + @"E", @"e", @"F", @"f", @"G", @"g", @"H", @"h", @"I", @"i", @"J", @"j", @"K", @"k", @"L", @"l", @"M", @"m", @"N", @"n", + @"O", @"o", @"P", @"p", @"Q", @"q", @"R", @"r", @"S", @"s", @"T", @"t", @"U", @"u", @"V", @"v", @"W", @"w", @"X", @"x", + @"Y", @"y", @"Z", @"z", @"-", @"-", @"-", @"\uFF0D", @"-", @"\u2010", @"-", @"\u2011", @"-", @"\u2012", @"-", @"\u2013", @"-", @"\u2014", @"-", @"\u2015", + @"-", @"\u2212", @"/", @"/", @"/", @"\uFF0F", @" ", @" ", @" ", @"\u3000", @" ", @"\u2060", @".", @".", @".", @"\uFF0E", nil]; + } +} + + + + + +#pragma mark - Metadata manager (phonenumberutil.js) functions - +/** + * Attempts to extract a possible number from the string passed in. This + * currently strips all leading characters that cannot be used to start a phone + * number. Characters that can be used to start a phone number are defined in + * the VALID_START_CHAR_PATTERN. If none of these characters are found in the + * number passed in, an empty string is returned. This function also attempts to + * strip off any alternative extensions or endings if two or more are present, + * such as in the case of: (530) 583-6985 x302/x2303. The second extension here + * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985 + * x2303. We remove the second extension so that the first number is parsed + * correctly. + * + * @param {string} number the string that might contain a phone number. + * @return {string} the number, stripped of any non-phone-number prefix (such as + * 'Tel:') or an empty string if no character used to start phone numbers + * (such as + or any digit) is found in the number. + */ +- (NSString *)extractPossibleNumber:(NSString *)number +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + number = [helper normalizeNonBreakingSpace:number]; + + NSString *possibleNumber = @""; + int start = [self stringPositionByRegex:number regex:VALID_START_CHAR_PATTERN]; + + if (start >= 0) + { + possibleNumber = [number substringFromIndex:start]; + // Remove trailing non-alpha non-numerical characters. + possibleNumber = [self replaceStringByRegex:possibleNumber regex:UNWANTED_END_CHAR_PATTERN withTemplate:@""]; + + // Check for extra numbers at the end. + int secondNumberStart = [self stringPositionByRegex:number regex:SECOND_NUMBER_START_PATTERN]; + if (secondNumberStart > 0) + { + possibleNumber = [possibleNumber substringWithRange:NSMakeRange(0, secondNumberStart - 1)]; + } + } + else + { + possibleNumber = @""; + } + + return possibleNumber; +} + + +/** + * Checks to see if the string of characters could possibly be a phone number at + * all. At the moment, checks to see that the string begins with at least 2 + * digits, ignoring any punctuation commonly found in phone numbers. This method + * does not require the number to be normalized in advance - but does assume + * that leading non-number symbols have been removed, such as by the method + * extractPossibleNumber. + * + * @param {string} number string to be checked for viability as a phone number. + * @return {boolean} NO if the number could be a phone number of some sort, + * otherwise NO. + */ +- (BOOL)isViablePhoneNumber:(NSString *)phoneNumber +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + phoneNumber = [helper normalizeNonBreakingSpace:phoneNumber]; + + if (phoneNumber.length < MIN_LENGTH_FOR_NSN_) + { + return NO; + } + + return [self matchesEntirely:VALID_PHONE_NUMBER_PATTERN string:phoneNumber]; +} + + +/** + * Normalizes a string of characters representing a phone number. This performs + * the following conversions: + * Punctuation is stripped. + * For ALPHA/VANITY numbers: + * Letters are converted to their numeric representation on a telephone + * keypad. The keypad used here is the one defined in ITU Recommendation + * E.161. This is only done if there are 3 or more letters in the number, + * to lessen the risk that such letters are typos. + * For other numbers: + * Wide-ascii digits are converted to normal ASCII (European) digits. + * Arabic-Indic numerals are converted to European numerals. + * Spurious alpha characters are stripped. + * + * @param {string} number a string of characters representing a phone number. + * @return {string} the normalized string version of the phone number. + */ +- (NSString *)normalizePhoneNumber:(NSString *)number +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + number = [helper normalizeNonBreakingSpace:number]; + + if ([self matchesEntirely:VALID_ALPHA_PHONE_PATTERN_STRING string:number]) + { + return [self normalizeHelper:number normalizationReplacements:ALL_NORMALIZATION_MAPPINGS removeNonMatches:true]; + } + else + { + return [self normalizeDigitsOnly:number]; + } + + return nil; +} + + +/** + * Normalizes a string of characters representing a phone number. This is a + * wrapper for normalize(String number) but does in-place normalization of the + * StringBuffer provided. + * + * @param {!goog.string.StringBuffer} number a StringBuffer of characters + * representing a phone number that will be normalized in place. + * @private + */ + +- (void)normalizeSB:(NSString **)number +{ + if (number == NULL) { + return; + } + + (*number) = [self normalizePhoneNumber:(*number)]; +} + + +/** + * Normalizes a string of characters representing a phone number. This converts + * wide-ascii and arabic-indic numerals to European numerals, and strips + * punctuation and alpha characters. + * + * @param {string} number a string of characters representing a phone number. + * @return {string} the normalized string version of the phone number. + */ +- (NSString *)normalizeDigitsOnly:(NSString *)number +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + number = [helper normalizeNonBreakingSpace:number]; + + return [self stringByReplacingOccurrencesString:number withMap:self.DIGIT_MAPPINGS removeNonMatches:YES]; +} + + +/** + * Converts all alpha characters in a number to their respective digits on a + * keypad, but retains existing formatting. Also converts wide-ascii digits to + * normal ascii digits, and converts Arabic-Indic numerals to European numerals. + * + * @param {string} number a string of characters representing a phone number. + * @return {string} the normalized string version of the phone number. + */ +- (NSString *)convertAlphaCharactersInNumber:(NSString *)number +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + number = [helper normalizeNonBreakingSpace:number]; + return [self stringByReplacingOccurrencesString:number withMap:ALL_NORMALIZATION_MAPPINGS removeNonMatches:NO]; +} + + +/** + * Gets the length of the geographical area code from the + * {@code national_number} field of the PhoneNumber object passed in, so that + * clients could use it to split a national significant number into geographical + * area code and subscriber number. It works in such a way that the resultant + * subscriber number should be diallable, at least on some devices. An example + * of how this could be used: + * + *
+ * var phoneUtil = getInstance();
+ * var number = phoneUtil.parse('16502530000', 'US');
+ * var nationalSignificantNumber =
+ *     phoneUtil.getNationalSignificantNumber(number);
+ * var areaCode;
+ * var subscriberNumber;
+ *
+ * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
+ * if (areaCodeLength > 0) {
+ *   areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
+ *   subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
+ * } else {
+ *   areaCode = '';
+ *   subscriberNumber = nationalSignificantNumber;
+ * }
+ * 
+ * + * N.B.: area code is a very ambiguous concept, so the I18N team generally + * recommends against using it for most purposes, but recommends using the more + * general {@code national_number} instead. Read the following carefully before + * deciding to use this method: + *
    + *
  • geographical area codes change over time, and this method honors those + * changes; therefore, it doesn't guarantee the stability of the result it + * produces. + *
  • subscriber numbers may not be diallable from all devices (notably + * mobile devices, which typically requires the full national_number to be + * dialled in most regions). + *
  • most non-geographical numbers have no area codes, including numbers + * from non-geographical entities. + *
  • some geographical numbers have no area codes. + *
+ * + * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for + * which clients want to know the length of the area code. + * @return {number} the length of area code of the PhoneNumber object passed in. + */ +- (int)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber error:(NSError **)error +{ + int res = 0; + @try { + res = [self getLengthOfGeographicalAreaCode:phoneNumber]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + } + return res; +} + + +- (int)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber +{ + NSString *regionCode = [self getRegionCodeForNumber:phoneNumber]; + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadata = [helper getMetadataForRegion:regionCode]; + + if (metadata == nil) { + return 0; + } + // If a country doesn't use a national prefix, and this number doesn't have + // an Italian leading zero, we assume it is a closed dialling plan with no + // area codes. + if (metadata.nationalPrefix == nil && phoneNumber.italianLeadingZero == NO) { + return 0; + } + + if ([self isNumberGeographical:phoneNumber] == NO) { + return 0; + } + + return [self getLengthOfNationalDestinationCode:phoneNumber]; +} + + +/** + * Gets the length of the national destination code (NDC) from the PhoneNumber + * object passed in, so that clients could use it to split a national + * significant number into NDC and subscriber number. The NDC of a phone number + * is normally the first group of digit(s) right after the country calling code + * when the number is formatted in the international format, if there is a + * subscriber number part that follows. An example of how this could be used: + * + *
+ * var phoneUtil = getInstance();
+ * var number = phoneUtil.parse('18002530000', 'US');
+ * var nationalSignificantNumber =
+ *     phoneUtil.getNationalSignificantNumber(number);
+ * var nationalDestinationCode;
+ * var subscriberNumber;
+ *
+ * var nationalDestinationCodeLength =
+ *     phoneUtil.getLengthOfNationalDestinationCode(number);
+ * if (nationalDestinationCodeLength > 0) {
+ *   nationalDestinationCode =
+ *       nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
+ *   subscriberNumber =
+ *       nationalSignificantNumber.substring(nationalDestinationCodeLength);
+ * } else {
+ *   nationalDestinationCode = '';
+ *   subscriberNumber = nationalSignificantNumber;
+ * }
+ * 
+ * + * Refer to the unittests to see the difference between this function and + * {@link #getLengthOfGeographicalAreaCode}. + * + * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for + * which clients want to know the length of the NDC. + * @return {number} the length of NDC of the PhoneNumber object passed in. + */ +- (int)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber error:(NSError **)error +{ + int res = 0; + + @try { + res = [self getLengthOfNationalDestinationCode:phoneNumber]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + } + + return res; +} + + +- (int)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber +{ + NBPhoneNumber *copiedProto = nil; + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + if ([NBMetadataHelper hasValue:phoneNumber.extension]) { + copiedProto = [phoneNumber copy]; + copiedProto.extension = nil; + } else { + copiedProto = phoneNumber; + } + + NSString *nationalSignificantNumber = [self format:copiedProto numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + NSMutableArray *numberGroups = [[self componentsSeparatedByRegex:nationalSignificantNumber regex:NON_DIGITS_PATTERN] mutableCopy]; + + // The pattern will start with '+COUNTRY_CODE ' so the first group will always + // be the empty string (before the + symbol) and the second group will be the + // country calling code. The third group will be area code if it is not the + // last group. + // NOTE: On IE the first group that is supposed to be the empty string does + // not appear in the array of number groups... so make the result on non-IE + // browsers to be that of IE. + if ([numberGroups count] > 0 && ((NSString *)[numberGroups objectAtIndex:0]).length <= 0) { + [numberGroups removeObjectAtIndex:0]; + } + + if ([numberGroups count] <= 2) { + return 0; + } + + NSArray *regionCodes = [helper regionCodeFromCountryCode:phoneNumber.countryCode]; + BOOL isExists = NO; + + for (NSString *regCode in regionCodes) + { + if ([regCode isEqualToString:@"AR"]) + { + isExists = YES; + break; + } + } + + if (isExists && [self getNumberType:phoneNumber] == NBEPhoneNumberTypeMOBILE) + { + // Argentinian mobile numbers, when formatted in the international format, + // are in the form of +54 9 NDC XXXX.... As a result, we take the length of + // the third group (NDC) and add 1 for the digit 9, which also forms part of + // the national significant number. + // + // TODO: Investigate the possibility of better modeling the metadata to make + // it easier to obtain the NDC. + return (int)((NSString *)[numberGroups objectAtIndex:2]).length + 1; + } + + return (int)((NSString *)[numberGroups objectAtIndex:1]).length; +} + + +/** + * Normalizes a string of characters representing a phone number by replacing + * all characters found in the accompanying map with the values therein, and + * stripping all other characters if removeNonMatches is NO. + * + * @param {string} number a string of characters representing a phone number. + * @param {!Object.} normalizationReplacements a mapping of + * characters to what they should be replaced by in the normalized version + * of the phone number. + * @param {boolean} removeNonMatches indicates whether characters that are not + * able to be replaced should be stripped from the number. If this is NO, + * they will be left unchanged in the number. + * @return {string} the normalized string version of the phone number. + * @private + */ +- (NSString *)normalizeHelper:(NSString *)sourceString normalizationReplacements:(NSDictionary*)normalizationReplacements + removeNonMatches:(BOOL)removeNonMatches +{ + NSMutableString *normalizedNumber = [[NSMutableString alloc] init]; + unichar character = 0; + NSString *newDigit = @""; + unsigned int numberLength = (unsigned int)sourceString.length; + + for (unsigned int i = 0; i= 0) + { + hasFound = YES; + } + + return (([nationalPrefixFormattingRule length] == 0) || hasFound); +} + + +/** + * Tests whether a phone number has a geographical association. It checks if + * the number is associated to a certain region in the country where it belongs + * to. Note that this doesn't verify if the number is actually in use. + * + * @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test. + * @return {boolean} NO if the phone number has a geographical association. + * @private + */ +- (BOOL)isNumberGeographical:(NBPhoneNumber*)phoneNumber +{ + NBEPhoneNumberType numberType = [self getNumberType:phoneNumber]; + // TODO: Include mobile phone numbers from countries like Indonesia, which + // has some mobile numbers that are geographical. + + BOOL containGeoMobileContries = + [GEO_MOBILE_COUNTRIES containsObject:phoneNumber.countryCode] && numberType == NBEPhoneNumberTypeMOBILE; + BOOL isFixedLine = (numberType == NBEPhoneNumberTypeFIXED_LINE); + BOOL isFixedLineOrMobile = (numberType == NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE); + return isFixedLine || isFixedLineOrMobile || containGeoMobileContries; +} + + +/** + * Helper function to check region code is not unknown or nil. + * + * @param {?string} regionCode the ISO 3166-1 two-letter region code. + * @return {boolean} NO if region code is valid. + * @private + */ +- (BOOL)isValidRegionCode:(NSString *)regionCode +{ + // In Java we check whether the regionCode is contained in supportedRegions + // that is built out of all the values of countryCallingCodeToRegionCodeMap + // (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY. + // In JS we check whether the regionCode is contained in the keys of + // countryToMetadata but since for non-geographical country calling codes + // (e.g. +800) we use the country calling codes instead of the region code as + // key in the map we have to make sure regionCode is not a number to prevent + // returning NO for non-geographical country calling codes. + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + return [NBMetadataHelper hasValue:regionCode] && [self isNaN:regionCode] && [helper getMetadataForRegion:regionCode.uppercaseString] != nil; +} + + +/** + * Helper function to check the country calling code is valid. + * + * @param {number} countryCallingCode the country calling code. + * @return {boolean} NO if country calling code code is valid. + * @private + */ +- (BOOL)hasValidCountryCallingCode:(NSNumber*)countryCallingCode +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + id res = [helper regionCodeFromCountryCode:countryCallingCode]; + if (res != nil) { + return YES; + } + + return NO; +} + + +/** + * Formats a phone number in the specified format using default rules. Note that + * this does not promise to produce a phone number that the user can dial from + * where they are - although we do format in either 'national' or + * 'international' format depending on what the client asks for, we do not + * currently support a more abbreviated format, such as for users in the same + * 'area' who could potentially dial the number without area code. Note that if + * the phone number has a country calling code of 0 or an otherwise invalid + * country calling code, we cannot work out which formatting rules to apply so + * we return the national significant number with no formatting applied. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @return {string} the formatted phone number. + */ +- (NSString *)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat error:(NSError**)error +{ + NSString *res = nil; + @try { + res = [self format:phoneNumber numberFormat:numberFormat]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + +- (NSString *)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + if ([phoneNumber.nationalNumber isEqualToNumber:@0] && [NBMetadataHelper hasValue:phoneNumber.rawInput]) { + // Unparseable numbers that kept their raw input just use that. + // This is the only case where a number can be formatted as E164 without a + // leading '+' symbol (but the original number wasn't parseable anyway). + // TODO: Consider removing the 'if' above so that unparseable strings + // without raw input format to the empty string instead of "+00" + /** @type {string} */ + NSString *rawInput = phoneNumber.rawInput; + if ([NBMetadataHelper hasValue:rawInput]) { + return rawInput; + } + } + + NSNumber *countryCallingCode = phoneNumber.countryCode; + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:phoneNumber]; + + if (numberFormat == NBEPhoneNumberFormatE164) + { + // Early exit for E164 case (even if the country calling code is invalid) + // since no formatting of the national number needs to be applied. + // Extensions are not formatted. + return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatE164 + formattedNationalNumber:nationalSignificantNumber formattedExtension:@""]; + } + + if ([self hasValidCountryCallingCode:countryCallingCode] == NO) + { + return nationalSignificantNumber; + } + + // Note getRegionCodeForCountryCode() is used because formatting information + // for regions which share a country calling code is contained by only one + // region for performance reasons. For example, for NANPA regions it will be + // contained in the metadata for US. + NSArray *regionCodeArray = [helper regionCodeFromCountryCode:countryCallingCode]; + NSString *regionCode = [regionCodeArray objectAtIndex:0]; + + // Metadata cannot be nil because the country calling code is valid (which + // means that the region code cannot be ZZ and must be one of our supported + // region codes). + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode]; + NSString *formattedExtension = [self maybeGetFormattedExtension:phoneNumber metadata:metadata numberFormat:numberFormat]; + NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadata phoneNumberFormat:numberFormat carrierCode:nil]; + + return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:numberFormat + formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension]; +} + + +/** + * Formats a phone number in the specified format using client-defined + * formatting rules. Note that if the phone number has a country calling code of + * zero or an otherwise invalid country calling code, we cannot work out things + * like whether there should be a national prefix applied, or how to format + * extensions, so we return the national significant number with no formatting + * applied. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @param {Array.} userDefinedFormats formatting + * rules specified by clients. + * @return {string} the formatted phone number. + */ +- (NSString *)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats error:(NSError**)error +{ + NSString *res = nil; + @try { + res = [self formatByPattern:number numberFormat:numberFormat userDefinedFormats:userDefinedFormats]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + + +- (NSString *)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats +{ + NSNumber *countryCallingCode = number.countryCode; + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number]; + + if ([self hasValidCountryCallingCode:countryCallingCode] == NO) { + return nationalSignificantNumber; + } + + // Note getRegionCodeForCountryCode() is used because formatting information + // for regions which share a country calling code is contained by only one + // region for performance reasons. For example, for NANPA regions it will be + // contained in the metadata for US. + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NSArray *regionCodes = [helper regionCodeFromCountryCode:countryCallingCode]; + NSString *regionCode = nil; + if (regionCodes != nil && regionCodes.count > 0) { + regionCode = [regionCodes objectAtIndex:0]; + } + + // Metadata cannot be nil because the country calling code is valid + /** @type {i18n.phonenumbers.PhoneMetadata} */ + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode]; + + NSString *formattedNumber = @""; + NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:userDefinedFormats + nationalNumber:nationalSignificantNumber]; + + if (formattingPattern == nil) { + // If no pattern above is matched, we format the number as a whole. + formattedNumber = nationalSignificantNumber; + } else { + // Before we do a replacement of the national prefix pattern $NP with the + // national prefix, we need to copy the rule so that subsequent replacements + // for different numbers have the appropriate national prefix. + NBNumberFormat *numFormatCopy = [formattingPattern copy]; + NSString *nationalPrefixFormattingRule = formattingPattern.nationalPrefixFormattingRule; + + if (nationalPrefixFormattingRule.length > 0) { + NSString *nationalPrefix = metadata.nationalPrefix; + if (nationalPrefix.length > 0) { + // Replace $NP with national prefix and $FG with the first group ($1). + nationalPrefixFormattingRule = [self replaceStringByRegex:nationalPrefixFormattingRule + regex:NP_PATTERN withTemplate:nationalPrefix]; + nationalPrefixFormattingRule = [self replaceStringByRegex:nationalPrefixFormattingRule + regex:FG_PATTERN withTemplate:@"\\$1"]; + numFormatCopy.nationalPrefixFormattingRule = nationalPrefixFormattingRule; + } else { + // We don't want to have a rule for how to format the national prefix if + // there isn't one. + numFormatCopy.nationalPrefixFormattingRule = @""; + } + } + + formattedNumber = [self formatNsnUsingPattern:nationalSignificantNumber + formattingPattern:numFormatCopy numberFormat:numberFormat carrierCode:nil]; + } + + NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadata numberFormat:numberFormat]; + + //NSLog(@"!@# prefixNumberWithCountryCallingCode called [%@]", formattedExtension); + return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:numberFormat + formattedNationalNumber:formattedNumber formattedExtension:formattedExtension]; +} + + +/** + * Formats a phone number in national format for dialing using the carrier as + * specified in the {@code carrierCode}. The {@code carrierCode} will always be + * used regardless of whether the phone number already has a preferred domestic + * carrier code stored. If {@code carrierCode} contains an empty string, returns + * the number in national format without any carrier code. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {string} carrierCode the carrier selection code to be used. + * @return {string} the formatted phone number in national format for dialing + * using the carrier as specified in the {@code carrierCode}. + */ +- (NSString *)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString *)carrierCode error:(NSError **)error +{ + NSString *res = nil; + @try { + res = [self formatNationalNumberWithCarrierCode:number carrierCode:carrierCode]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + } + return res; +} + + +- (NSString *)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString *)carrierCode +{ + NSNumber *countryCallingCode = number.countryCode; + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number]; + + if ([self hasValidCountryCallingCode:countryCallingCode] == NO) { + return nationalSignificantNumber; + } + + // Note getRegionCodeForCountryCode() is used because formatting information + // for regions which share a country calling code is contained by only one + // region for performance reasons. For example, for NANPA regions it will be + // contained in the metadata for US. + NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode]; + // Metadata cannot be nil because the country calling code is valid. + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode]; + NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadata numberFormat:NBEPhoneNumberFormatNATIONAL]; + NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadata + phoneNumberFormat:NBEPhoneNumberFormatNATIONAL carrierCode:carrierCode]; + return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatNATIONAL + formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension]; +} + + +/** + * @param {number} countryCallingCode + * @param {?string} regionCode + * @return {i18n.phonenumbers.PhoneMetadata} + * @private + */ +- (NBPhoneMetaData*)getMetadataForRegionOrCallingCode:(NSNumber*)countryCallingCode regionCode:(NSString *)regionCode +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + return [NB_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:regionCode] ? + [helper getMetadataForNonGeographicalRegion:countryCallingCode] : [helper getMetadataForRegion:regionCode]; +} + + +/** + * Formats a phone number in national format for dialing using the carrier as + * specified in the preferred_domestic_carrier_code field of the PhoneNumber + * object passed in. If that is missing, use the {@code fallbackCarrierCode} + * passed in instead. If there is no {@code preferred_domestic_carrier_code}, + * and the {@code fallbackCarrierCode} contains an empty string, return the + * number in national format without any carrier code. + * + *

Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier + * code passed in should take precedence over the number's + * {@code preferred_domestic_carrier_code} when formatting. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {string} fallbackCarrierCode the carrier selection code to be used, if + * none is found in the phone number itself. + * @return {string} the formatted phone number in national format for dialing + * using the number's preferred_domestic_carrier_code, or the + * {@code fallbackCarrierCode} passed in if none is found. + */ +- (NSString *)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number + fallbackCarrierCode:(NSString *)fallbackCarrierCode error:(NSError **)error +{ + NSString *res = nil; + @try { + res = [self formatNationalNumberWithCarrierCode:number carrierCode:fallbackCarrierCode]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + } + + return res; +} + + +- (NSString *)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number fallbackCarrierCode:(NSString *)fallbackCarrierCode +{ + NSString *domesticCarrierCode = number.preferredDomesticCarrierCode != nil ? number.preferredDomesticCarrierCode : fallbackCarrierCode; + return [self formatNationalNumberWithCarrierCode:number carrierCode:domesticCarrierCode]; +} + + +/** + * Returns a number formatted in such a way that it can be dialed from a mobile + * phone in a specific region. If the number cannot be reached from the region + * (e.g. some countries block toll-free numbers from being called outside of the + * country), the method returns an empty string. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {string} regionCallingFrom the region where the call is being placed. + * @param {boolean} withFormatting whether the number should be returned with + * formatting symbols, such as spaces and dashes. + * @return {string} the formatted phone number. + */ +- (NSString *)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom withFormatting:(BOOL)withFormatting + error:(NSError**)error +{ + NSString *res = nil; + @try { + res = [self formatNumberForMobileDialing:number regionCallingFrom:regionCallingFrom withFormatting:withFormatting]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + + +- (NSString *)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom withFormatting:(BOOL)withFormatting +{ + NSNumber *countryCallingCode = number.countryCode; + + if ([self hasValidCountryCallingCode:countryCallingCode] == NO) { + return [NBMetadataHelper hasValue:number.rawInput] ? number.rawInput : @""; + } + + NSString *formattedNumber = @""; + // Clear the extension, as that part cannot normally be dialed together with + // the main number. + NBPhoneNumber *numberNoExt = [number copy]; + numberNoExt.extension = @""; + + NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode]; + if ([regionCallingFrom isEqualToString:regionCode]) { + NBEPhoneNumberType numberType = [self getNumberType:numberNoExt]; + BOOL isFixedLineOrMobile = (numberType == NBEPhoneNumberTypeFIXED_LINE) || (numberType == NBEPhoneNumberTypeMOBILE) || + (numberType == NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE); + // Carrier codes may be needed in some countries. We handle this here. + if ([regionCode isEqualToString:@"CO"] && numberType == NBEPhoneNumberTypeFIXED_LINE) { + formattedNumber = [self formatNationalNumberWithCarrierCode:numberNoExt + carrierCode:COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX]; + } else if ([regionCode isEqualToString:@"BR"] && isFixedLineOrMobile) { + formattedNumber = [NBMetadataHelper hasValue:numberNoExt.preferredDomesticCarrierCode] ? + [self formatNationalNumberWithPreferredCarrierCode:numberNoExt fallbackCarrierCode:@""] : @""; + // Brazilian fixed line and mobile numbers need to be dialed with a + // carrier code when called within Brazil. Without that, most of the + // carriers won't connect the call. Because of that, we return an + // empty string here. + } else { + // For NANPA countries, non-geographical countries, and Mexican fixed + // line and mobile numbers, we output international format for numbersi + // that can be dialed internationally as that always works. + if ((countryCallingCode.unsignedIntegerValue == NANPA_COUNTRY_CODE_ || + [regionCode isEqualToString:NB_REGION_CODE_FOR_NON_GEO_ENTITY] || + // MX fixed line and mobile numbers should always be formatted in + // international format, even when dialed within MX. For national + // format to work, a carrier code needs to be used, and the correct + // carrier code depends on if the caller and callee are from the + // same local area. It is trickier to get that to work correctly than + // using international format, which is tested to work fine on all + // carriers. + ([regionCode isEqualToString:@"MX"] && isFixedLineOrMobile)) && [self canBeInternationallyDialled:numberNoExt]) { + formattedNumber = [self format:numberNoExt numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + } else { + formattedNumber = [self format:numberNoExt numberFormat:NBEPhoneNumberFormatNATIONAL]; + } + } + } else if ([self canBeInternationallyDialled:numberNoExt]) { + return withFormatting ? [self format:numberNoExt numberFormat:NBEPhoneNumberFormatINTERNATIONAL] : + [self format:numberNoExt numberFormat:NBEPhoneNumberFormatE164]; + } + + return withFormatting ? + formattedNumber : [self normalizeHelper:formattedNumber normalizationReplacements:DIALLABLE_CHAR_MAPPINGS removeNonMatches:YES]; +} + + +/** + * Formats a phone number for out-of-country dialing purposes. If no + * regionCallingFrom is supplied, we format the number in its INTERNATIONAL + * format. If the country calling code is the same as that of the region where + * the number is from, then NATIONAL formatting will be applied. + * + *

If the number itself has a country calling code of zero or an otherwise + * invalid country calling code, then we return the number with no formatting + * applied. + * + *

Note this function takes care of the case for calling inside of NANPA and + * between Russia and Kazakhstan (who share the same country calling code). In + * those cases, no international prefix is used. For regions which have multiple + * international prefixes, the number in its INTERNATIONAL format will be + * returned instead. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be + * formatted. + * @param {string} regionCallingFrom the region where the call is being placed. + * @return {string} the formatted phone number. + */ +- (NSString *)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom error:(NSError**)error +{ + NSString *res = nil; + @try { + res = [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + + return res; +} + +- (NSString *)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom +{ + if ([self isValidRegionCode:regionCallingFrom] == NO) { + return [self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + } + + NSNumber *countryCallingCode = [number.countryCode copy]; + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number]; + + if ([self hasValidCountryCallingCode:countryCallingCode] == NO) { + return nationalSignificantNumber; + } + + if (countryCallingCode.unsignedIntegerValue == NANPA_COUNTRY_CODE_) { + if ([self isNANPACountry:regionCallingFrom]) { + // For NANPA regions, return the national format for these regions but + // prefix it with the country calling code. + return [NSString stringWithFormat:@"%@ %@", countryCallingCode, [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]]; + } + } else if ([countryCallingCode isEqualToNumber:[self getCountryCodeForValidRegion:regionCallingFrom error:nil]]) { + // If regions share a country calling code, the country calling code need + // not be dialled. This also applies when dialling within a region, so this + // if clause covers both these cases. Technically this is the case for + // dialling from La Reunion to other overseas departments of France (French + // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover + // this edge case for now and for those cases return the version including + // country calling code. Details here: + // http://www.petitfute.com/voyage/225-info-pratiques-reunion + return [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]; + } + + // Metadata cannot be nil because we checked 'isValidRegionCode()' above. + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadataForRegionCallingFrom = [helper getMetadataForRegion:regionCallingFrom]; + NSString *internationalPrefix = metadataForRegionCallingFrom.internationalPrefix; + + // For regions that have multiple international prefixes, the international + // format of the number is returned, unless there is a preferred international + // prefix. + NSString *internationalPrefixForFormatting = @""; + + if ([self matchesEntirely:UNIQUE_INTERNATIONAL_PREFIX string:internationalPrefix]) { + internationalPrefixForFormatting = internationalPrefix; + } else if ([NBMetadataHelper hasValue:metadataForRegionCallingFrom.preferredInternationalPrefix]) { + internationalPrefixForFormatting = metadataForRegionCallingFrom.preferredInternationalPrefix; + } + + NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode]; + // Metadata cannot be nil because the country calling code is valid. + NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode]; + NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadataForRegion + phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL carrierCode:nil]; + NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadataForRegion numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + + NSString *hasLenth = [NSString stringWithFormat:@"%@ %@ %@%@", internationalPrefixForFormatting, countryCallingCode, formattedNationalNumber, formattedExtension]; + NSString *hasNotLength = [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL + formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension]; + + return internationalPrefixForFormatting.length > 0 ? hasLenth:hasNotLength; +} + + +/** + * A helper function that is used by format and formatByPattern. + * + * @param {number} countryCallingCode the country calling code. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @param {string} formattedNationalNumber + * @param {string} formattedExtension + * @return {string} the formatted phone number. + * @private + */ +- (NSString *)prefixNumberWithCountryCallingCode:(NSNumber*)countryCallingCode phoneNumberFormat:(NBEPhoneNumberFormat)numberFormat + formattedNationalNumber:(NSString *)formattedNationalNumber + formattedExtension:(NSString *)formattedExtension +{ + switch (numberFormat) + { + case NBEPhoneNumberFormatE164: + return [NSString stringWithFormat:@"+%@%@%@", countryCallingCode, formattedNationalNumber, formattedExtension]; + case NBEPhoneNumberFormatINTERNATIONAL: + return [NSString stringWithFormat:@"+%@ %@%@", countryCallingCode, formattedNationalNumber, formattedExtension]; + case NBEPhoneNumberFormatRFC3966: + return [NSString stringWithFormat:@"%@+%@-%@%@", RFC3966_PREFIX, countryCallingCode, formattedNationalNumber, formattedExtension]; + case NBEPhoneNumberFormatNATIONAL: + default: + return [NSString stringWithFormat:@"%@%@", formattedNationalNumber, formattedExtension]; + } +} + + +/** + * Formats a phone number using the original phone number format that the number + * is parsed from. The original format is embedded in the country_code_source + * field of the PhoneNumber object passed in. If such information is missing, + * the number will be formatted into the NATIONAL format by default. When the + * number contains a leading zero and this is unexpected for this country, or we + * don't have a formatting pattern for the number, the method returns the raw + * input when it is available. + * + * Note this method guarantees no digit will be inserted, removed or modified as + * a result of formatting. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to + * be formatted in its original number format. + * @param {string} regionCallingFrom the region whose IDD needs to be prefixed + * if the original number has one. + * @return {string} the formatted phone number in its original number format. + */ +- (NSString *)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom error:(NSError **)error +{ + NSString *res = nil; + @try { + res = [self formatInOriginalFormat:number regionCallingFrom:regionCallingFrom]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + + return res; +} + + +- (NSString *)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + if ([NBMetadataHelper hasValue:number.rawInput] && ([self hasUnexpectedItalianLeadingZero:number] || [self hasFormattingPatternForNumber:number] == NO)) { + // We check if we have the formatting pattern because without that, we might + // format the number as a group without national prefix. + return number.rawInput; + } + + if (number.countryCodeSource == nil) { + return [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]; + } + + NSString *formattedNumber = @""; + + switch ([number.countryCodeSource integerValue]) + { + case NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN: + formattedNumber = [self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + break; + case NBECountryCodeSourceFROM_NUMBER_WITH_IDD: + formattedNumber = [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom]; + break; + case NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN: + formattedNumber = [[self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL] substringFromIndex:1]; + break; + case NBECountryCodeSourceFROM_DEFAULT_COUNTRY: + // Fall-through to default case. + default: + { + NSString *regionCode = [self getRegionCodeForCountryCode:number.countryCode]; + // We strip non-digits from the NDD here, and from the raw input later, + // so that we can compare them easily. + NSString *nationalPrefix = [self getNddPrefixForRegion:regionCode stripNonDigits:YES]; + NSString *nationalFormat = [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]; + if (nationalPrefix == nil || nationalPrefix.length == 0) + { + // If the region doesn't have a national prefix at all, we can safely + // return the national format without worrying about a national prefix + // being added. + formattedNumber = nationalFormat; + break; + } + // Otherwise, we check if the original number was entered with a national + // prefix. + if ([self rawInputContainsNationalPrefix:number.rawInput nationalPrefix:nationalPrefix regionCode:regionCode]) + { + // If so, we can safely return the national format. + formattedNumber = nationalFormat; + break; + } + // Metadata cannot be nil here because getNddPrefixForRegion() (above) + // returns nil if there is no metadata for the region. + NBPhoneMetaData *metadata = [helper getMetadataForRegion:regionCode]; + NSString *nationalNumber = [self getNationalSignificantNumber:number]; + NBNumberFormat *formatRule = [self chooseFormattingPatternForNumber:metadata.numberFormats nationalNumber:nationalNumber]; + // The format rule could still be nil here if the national number was 0 + // and there was no raw input (this should not be possible for numbers + // generated by the phonenumber library as they would also not have a + // country calling code and we would have exited earlier). + if (formatRule == nil) + { + formattedNumber = nationalFormat; + break; + } + // When the format we apply to this number doesn't contain national + // prefix, we can just return the national format. + // TODO: Refactor the code below with the code in + // isNationalPrefixPresentIfRequired. + NSString *candidateNationalPrefixRule = formatRule.nationalPrefixFormattingRule; + // We assume that the first-group symbol will never be _before_ the + // national prefix. + NSRange firstGroupRange = [candidateNationalPrefixRule rangeOfString:@"$1"]; + if (firstGroupRange.location == NSNotFound) + { + formattedNumber = nationalFormat; + break; + } + + if (firstGroupRange.location <= 0) + { + formattedNumber = nationalFormat; + break; + } + candidateNationalPrefixRule = [candidateNationalPrefixRule substringWithRange:NSMakeRange(0, firstGroupRange.location)]; + candidateNationalPrefixRule = [self normalizeDigitsOnly:candidateNationalPrefixRule]; + if (candidateNationalPrefixRule.length == 0) + { + // National prefix not used when formatting this number. + formattedNumber = nationalFormat; + break; + } + // Otherwise, we need to remove the national prefix from our output. + NBNumberFormat *numFormatCopy = [formatRule copy]; + numFormatCopy.nationalPrefixFormattingRule = nil; + formattedNumber = [self formatByPattern:number numberFormat:NBEPhoneNumberFormatNATIONAL userDefinedFormats:@[numFormatCopy]]; + break; + } + } + + NSString *rawInput = number.rawInput; + // If no digit is inserted/removed/modified as a result of our formatting, we + // return the formatted phone number; otherwise we return the raw input the + // user entered. + if (formattedNumber != nil && rawInput.length > 0) + { + NSString *normalizedFormattedNumber = [self normalizeHelper:formattedNumber normalizationReplacements:DIALLABLE_CHAR_MAPPINGS removeNonMatches:YES]; + /** @type {string} */ + NSString *normalizedRawInput = [self normalizeHelper:rawInput normalizationReplacements:DIALLABLE_CHAR_MAPPINGS removeNonMatches:YES]; + + if ([normalizedFormattedNumber isEqualToString:normalizedRawInput] == NO) + { + formattedNumber = rawInput; + } + } + return formattedNumber; +} + + +/** + * Check if rawInput, which is assumed to be in the national format, has a + * national prefix. The national prefix is assumed to be in digits-only form. + * @param {string} rawInput + * @param {string} nationalPrefix + * @param {string} regionCode + * @return {boolean} + * @private + */ +- (BOOL)rawInputContainsNationalPrefix:(NSString *)rawInput nationalPrefix:(NSString *)nationalPrefix regionCode:(NSString *)regionCode +{ + BOOL isValid = NO; + NSString *normalizedNationalNumber = [self normalizeDigitsOnly:rawInput]; + if ([self isStartingStringByRegex:normalizedNationalNumber regex:nationalPrefix]) + { + // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the + // national prefix when written without it (e.g. 0777123) if we just do + // prefix matching. To tackle that, we check the validity of the number if + // the assumed national prefix is removed (777123 won't be valid in + // Japan). + NSString *subString = [normalizedNationalNumber substringFromIndex:nationalPrefix.length]; + NSError *anError = nil; + isValid = [self isValidNumber:[self parse:subString defaultRegion:regionCode error:&anError]]; + + if (anError != nil) + return NO; + } + return isValid; +} + + +/** + * Returns NO if a number is from a region whose national significant number + * couldn't contain a leading zero, but has the italian_leading_zero field set + * to NO. + * @param {i18n.phonenumbers.PhoneNumber} number + * @return {boolean} + * @private + */ +- (BOOL)hasUnexpectedItalianLeadingZero:(NBPhoneNumber*)number +{ + return number.italianLeadingZero && [self isLeadingZeroPossible:number.countryCode] == NO; +} + + +/** + * @param {i18n.phonenumbers.PhoneNumber} number + * @return {boolean} + * @private + */ +- (BOOL)hasFormattingPatternForNumber:(NBPhoneNumber*)number +{ + NSNumber *countryCallingCode = number.countryCode; + NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCallingCode]; + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:phoneNumberRegion]; + + if (metadata == nil) + { + return NO; + } + + NSString *nationalNumber = [self getNationalSignificantNumber:number]; + NBNumberFormat *formatRule = [self chooseFormattingPatternForNumber:metadata.numberFormats nationalNumber:nationalNumber]; + return formatRule != nil; +} + + +/** + * Formats a phone number for out-of-country dialing purposes. + * + * Note that in this version, if the number was entered originally using alpha + * characters and this version of the number is stored in raw_input, this + * representation of the number will be used rather than the digit + * representation. Grouping information, as specified by characters such as '-' + * and ' ', will be retained. + * + *

Caveats:

+ *
    + *
  • This will not produce good results if the country calling code is both + * present in the raw input _and_ is the start of the national number. This is + * not a problem in the regions which typically use alpha numbers. + *
  • This will also not produce good results if the raw input has any grouping + * information within the first three digits of the national number, and if the + * function needs to strip preceding digits/words in the raw input before these + * digits. Normally people group the first three digits together so this is not + * a huge problem - and will be fixed if it proves to be so. + *
+ * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to + * be formatted. + * @param {string} regionCallingFrom the region where the call is being placed. + * @return {string} the formatted phone number. + */ +- (NSString *)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom error:(NSError **)error +{ + NSString *res = nil; + @try { + res = [self formatOutOfCountryKeepingAlphaChars:number regionCallingFrom:regionCallingFrom]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + + +- (NSString *)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString *)regionCallingFrom +{ + NSString *rawInput = number.rawInput; + // If there is no raw input, then we can't keep alpha characters because there + // aren't any. In this case, we return formatOutOfCountryCallingNumber. + if (rawInput == nil || rawInput.length == 0) + { + return [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom]; + } + + NSNumber *countryCode = number.countryCode; + if ([self hasValidCountryCallingCode:countryCode] == NO) + { + return rawInput; + } + // Strip any prefix such as country calling code, IDD, that was present. We do + // this by comparing the number in raw_input with the parsed number. To do + // this, first we normalize punctuation. We retain number grouping symbols + // such as ' ' only. + rawInput = [self normalizeHelper:rawInput normalizationReplacements:ALL_PLUS_NUMBER_GROUPING_SYMBOLS removeNonMatches:NO]; + //NSLog(@"---- formatOutOfCountryKeepingAlphaChars normalizeHelper rawInput [%@]", rawInput); + // Now we trim everything before the first three digits in the parsed number. + // We choose three because all valid alpha numbers have 3 digits at the start + // - if it does not, then we don't trim anything at all. Similarly, if the + // national number was less than three digits, we don't trim anything at all. + NSString *nationalNumber = [self getNationalSignificantNumber:number]; + if (nationalNumber.length > 3) + { + int firstNationalNumberDigit = [self indexOfStringByString:rawInput target:[nationalNumber substringWithRange:NSMakeRange(0, 3)]]; + if (firstNationalNumberDigit != -1) + { + rawInput = [rawInput substringFromIndex:firstNationalNumberDigit]; + } + } + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadataForRegionCallingFrom = [helper getMetadataForRegion:regionCallingFrom]; + + if (countryCode.unsignedIntegerValue == NANPA_COUNTRY_CODE_) { + if ([self isNANPACountry:regionCallingFrom]) { + return [NSString stringWithFormat:@"%@ %@", countryCode, rawInput]; + } + } else if (metadataForRegionCallingFrom != nil && [countryCode isEqualToNumber:[self getCountryCodeForValidRegion:regionCallingFrom error:nil]]) { + NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:metadataForRegionCallingFrom.numberFormats + nationalNumber:nationalNumber]; + if (formattingPattern == nil) { + // If no pattern above is matched, we format the original input. + return rawInput; + } + + NBNumberFormat *newFormat = [formattingPattern copy]; + // The first group is the first group of digits that the user wrote + // together. + newFormat.pattern = @"(\\d+)(.*)"; + // Here we just concatenate them back together after the national prefix + // has been fixed. + newFormat.format = @"$1$2"; + // Now we format using this pattern instead of the default pattern, but + // with the national prefix prefixed if necessary. + // This will not work in the cases where the pattern (and not the leading + // digits) decide whether a national prefix needs to be used, since we have + // overridden the pattern to match anything, but that is not the case in the + // metadata to date. + + return [self formatNsnUsingPattern:rawInput formattingPattern:newFormat numberFormat:NBEPhoneNumberFormatNATIONAL carrierCode:nil]; + } + + NSString *internationalPrefixForFormatting = @""; + // If an unsupported region-calling-from is entered, or a country with + // multiple international prefixes, the international format of the number is + // returned, unless there is a preferred international prefix. + if (metadataForRegionCallingFrom != nil) { + NSString *internationalPrefix = metadataForRegionCallingFrom.internationalPrefix; + internationalPrefixForFormatting = + [self matchesEntirely:UNIQUE_INTERNATIONAL_PREFIX string:internationalPrefix] ? internationalPrefix : metadataForRegionCallingFrom.preferredInternationalPrefix; + } + + NSString *regionCode = [self getRegionCodeForCountryCode:countryCode]; + // Metadata cannot be nil because the country calling code is valid. + NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode]; + NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadataForRegion numberFormat:NBEPhoneNumberFormatINTERNATIONAL]; + + if (internationalPrefixForFormatting.length > 0) { + return [NSString stringWithFormat:@"%@ %@ %@%@", internationalPrefixForFormatting, countryCode, rawInput, formattedExtension]; + } else { + // Invalid region entered as country-calling-from (so no metadata was found + // for it) or the region chosen has multiple international dialling + // prefixes. + return [self prefixNumberWithCountryCallingCode:countryCode phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL formattedNationalNumber:rawInput formattedExtension:formattedExtension]; + } +} + + +/** + * Note in some regions, the national number can be written in two completely + * different ways depending on whether it forms part of the NATIONAL format or + * INTERNATIONAL format. The numberFormat parameter here is used to specify + * which format to use for those cases. If a carrierCode is specified, this will + * be inserted into the formatted string to replace $CC. + * + * @param {string} number a string of characters representing a phone number. + * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the + * region that we think this number is from. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @param {string=} opt_carrierCode + * @return {string} the formatted phone number. + * @private + */ +- (NSString *)formatNsn:(NSString *)phoneNumber metadata:(NBPhoneMetaData*)metadata phoneNumberFormat:(NBEPhoneNumberFormat)numberFormat carrierCode:(NSString *)opt_carrierCode +{ + NSMutableArray *intlNumberFormats = metadata.intlNumberFormats; + // When the intlNumberFormats exists, we use that to format national number + // for the INTERNATIONAL format instead of using the numberDesc.numberFormats. + NSArray *availableFormats = ([intlNumberFormats count] <= 0 || numberFormat == NBEPhoneNumberFormatNATIONAL) ? metadata.numberFormats : intlNumberFormats; + NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:availableFormats nationalNumber:phoneNumber]; + + if (formattingPattern == nil) { + return phoneNumber; + } + + return [self formatNsnUsingPattern:phoneNumber formattingPattern:formattingPattern numberFormat:numberFormat carrierCode:opt_carrierCode]; +} + + +/** + * @param {Array.} availableFormats the + * available formats the phone number could be formatted into. + * @param {string} nationalNumber a string of characters representing a phone + * number. + * @return {i18n.phonenumbers.NumberFormat} + * @private + */ +- (NBNumberFormat*)chooseFormattingPatternForNumber:(NSArray*)availableFormats nationalNumber:(NSString *)nationalNumber +{ + for (NBNumberFormat *numFormat in availableFormats) { + unsigned int size = (unsigned int)[numFormat.leadingDigitsPatterns count]; + // We always use the last leading_digits_pattern, as it is the most detailed. + if (size == 0 || [self stringPositionByRegex:nationalNumber regex:[numFormat.leadingDigitsPatterns lastObject]] == 0) { + if ([self matchesEntirely:numFormat.pattern string:nationalNumber]) { + return numFormat; + } + } + } + + return nil; +} + + +/** + * Note that carrierCode is optional - if nil or an empty string, no carrier + * code replacement will take place. + * + * @param {string} nationalNumber a string of characters representing a phone + * number. + * @param {i18n.phonenumbers.NumberFormat} formattingPattern the formatting rule + * the phone number should be formatted into. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @param {string=} opt_carrierCode + * @return {string} the formatted phone number. + * @private + */ +- (NSString *)formatNsnUsingPattern:(NSString *)nationalNumber formattingPattern:(NBNumberFormat*)formattingPattern numberFormat:(NBEPhoneNumberFormat)numberFormat carrierCode:(NSString *)opt_carrierCode +{ + NSString *numberFormatRule = formattingPattern.format; + NSString *domesticCarrierCodeFormattingRule = formattingPattern.domesticCarrierCodeFormattingRule; + NSString *formattedNationalNumber = @""; + + if (numberFormat == NBEPhoneNumberFormatNATIONAL && [NBMetadataHelper hasValue:opt_carrierCode] && domesticCarrierCodeFormattingRule.length > 0) { + // Replace the $CC in the formatting rule with the desired carrier code. + NSString *carrierCodeFormattingRule = [self replaceStringByRegex:domesticCarrierCodeFormattingRule regex:CC_PATTERN withTemplate:opt_carrierCode]; + // Now replace the $FG in the formatting rule with the first group and + // the carrier code combined in the appropriate way. + numberFormatRule = [self replaceFirstStringByRegex:numberFormatRule regex:FIRST_GROUP_PATTERN + withTemplate:carrierCodeFormattingRule]; + formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:numberFormatRule]; + } else { + // Use the national prefix formatting rule instead. + NSString *nationalPrefixFormattingRule = formattingPattern.nationalPrefixFormattingRule; + if (numberFormat == NBEPhoneNumberFormatNATIONAL && [NBMetadataHelper hasValue:nationalPrefixFormattingRule]) { + NSString *replacePattern = [self replaceFirstStringByRegex:numberFormatRule regex:FIRST_GROUP_PATTERN withTemplate:nationalPrefixFormattingRule]; + formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:replacePattern]; + } else { + formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:numberFormatRule]; + } + } + + if (numberFormat == NBEPhoneNumberFormatRFC3966) { + // Strip any leading punctuation. + formattedNationalNumber = [self replaceStringByRegex:formattedNationalNumber regex:[NSString stringWithFormat:@"^%@", SEPARATOR_PATTERN] withTemplate:@""]; + + // Replace the rest with a dash between each number group. + formattedNationalNumber = [self replaceStringByRegex:formattedNationalNumber regex:SEPARATOR_PATTERN withTemplate:@"-"]; + } + return formattedNationalNumber; +} + + +/** + * Gets a valid number for the specified region. + * + * @param {string} regionCode the region for which an example number is needed. + * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the + * specified region. Returns nil when the metadata does not contain such + * information, or the region 001 is passed in. For 001 (representing non- + * geographical numbers), call {@link #getExampleNumberForNonGeoEntity} + * instead. + */ +- (NBPhoneNumber*)getExampleNumber:(NSString *)regionCode error:(NSError *__autoreleasing *)error +{ + NBPhoneNumber *res = [self getExampleNumberForType:regionCode type:NBEPhoneNumberTypeFIXED_LINE error:error]; + return res; +} + + +/** + * Gets a valid number for the specified region and number type. + * + * @param {string} regionCode the region for which an example number is needed. + * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is + * needed. + * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified + * region and type. Returns nil when the metadata does not contain such + * information or if an invalid region or region 001 was entered. + * For 001 (representing non-geographical numbers), call + * {@link #getExampleNumberForNonGeoEntity} instead. + */ +- (NBPhoneNumber*)getExampleNumberForType:(NSString *)regionCode type:(NBEPhoneNumberType)type error:(NSError *__autoreleasing *)error +{ + NBPhoneNumber *res = nil; + + if ([self isValidRegionCode:regionCode] == NO) { + return nil; + } + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + NBPhoneNumberDesc *desc = [self getNumberDescByType:[helper getMetadataForRegion:regionCode] type:type]; + + if ([NBMetadataHelper hasValue:desc.exampleNumber ]) { + return [self parse:desc.exampleNumber defaultRegion:regionCode error:error]; + } + + return res; +} + + +/** + * Gets a valid number for the specified country calling code for a + * non-geographical entity. + * + * @param {number} countryCallingCode the country calling code for a + * non-geographical entity. + * @return {i18n.phonenumbers.PhoneNumber} a valid number for the + * non-geographical entity. Returns nil when the metadata does not contain + * such information, or the country calling code passed in does not belong + * to a non-geographical entity. + */ +- (NBPhoneNumber*)getExampleNumberForNonGeoEntity:(NSNumber *)countryCallingCode error:(NSError *__autoreleasing *)error +{ + NBPhoneNumber *res = nil; + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadata = [helper getMetadataForNonGeographicalRegion:countryCallingCode]; + + if (metadata != nil) { + NBPhoneNumberDesc *desc = metadata.generalDesc; + if ([NBMetadataHelper hasValue:desc.exampleNumber]) { + NSString *callCode = [NSString stringWithFormat:@"+%@%@", countryCallingCode, desc.exampleNumber]; + return [self parse:callCode defaultRegion:NB_UNKNOWN_REGION error:error]; + } + } + + return res; +} + + +/** + * Gets the formatted extension of a phone number, if the phone number had an + * extension specified. If not, it returns an empty string. + * + * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have + * an extension. + * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the + * region that we think this number is from. + * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the + * phone number should be formatted into. + * @return {string} the formatted extension if any. + * @private + */ +- (NSString *)maybeGetFormattedExtension:(NBPhoneNumber*)number metadata:(NBPhoneMetaData*)metadata numberFormat:(NBEPhoneNumberFormat)numberFormat +{ + if ([NBMetadataHelper hasValue:number.extension] == NO) { + return @""; + } else { + if (numberFormat == NBEPhoneNumberFormatRFC3966) { + return [NSString stringWithFormat:@"%@%@", RFC3966_EXTN_PREFIX, number.extension]; + } else { + if ([NBMetadataHelper hasValue:metadata.preferredExtnPrefix]) { + return [NSString stringWithFormat:@"%@%@", metadata.preferredExtnPrefix, number.extension]; + } else { + return [NSString stringWithFormat:@"%@%@", DEFAULT_EXTN_PREFIX, number.extension]; + } + } + } +} + + +/** + * @param {i18n.phonenumbers.PhoneMetadata} metadata + * @param {i18n.phonenumbers.PhoneNumberType} type + * @return {i18n.phonenumbers.PhoneNumberDesc} + * @private + */ +- (NBPhoneNumberDesc*)getNumberDescByType:(NBPhoneMetaData*)metadata type:(NBEPhoneNumberType)type +{ + switch (type) + { + case NBEPhoneNumberTypePREMIUM_RATE: + return metadata.premiumRate; + case NBEPhoneNumberTypeTOLL_FREE: + return metadata.tollFree; + case NBEPhoneNumberTypeMOBILE: + if (metadata.mobile == nil) return metadata.generalDesc; + return metadata.mobile; + case NBEPhoneNumberTypeFIXED_LINE: + case NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE: + if (metadata.fixedLine == nil) return metadata.generalDesc; + return metadata.fixedLine; + case NBEPhoneNumberTypeSHARED_COST: + return metadata.sharedCost; + case NBEPhoneNumberTypeVOIP: + return metadata.voip; + case NBEPhoneNumberTypePERSONAL_NUMBER: + return metadata.personalNumber; + case NBEPhoneNumberTypePAGER: + return metadata.pager; + case NBEPhoneNumberTypeUAN: + return metadata.uan; + case NBEPhoneNumberTypeVOICEMAIL: + return metadata.voicemail; + default: + return metadata.generalDesc; + } +} + +/** + * Gets the type of a phone number. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want + * to know the type. + * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number. + */ +- (NBEPhoneNumberType)getNumberType:(NBPhoneNumber*)phoneNumber +{ + NSString *regionCode = [self getRegionCodeForNumber:phoneNumber]; + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:phoneNumber.countryCode regionCode:regionCode]; + if (metadata == nil) + { + return NBEPhoneNumberTypeUNKNOWN; + } + + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:phoneNumber]; + return [self getNumberTypeHelper:nationalSignificantNumber metadata:metadata]; +} + + +/** + * @param {string} nationalNumber + * @param {i18n.phonenumbers.PhoneMetadata} metadata + * @return {i18n.phonenumbers.PhoneNumberType} + * @private + */ +- (NBEPhoneNumberType)getNumberTypeHelper:(NSString *)nationalNumber metadata:(NBPhoneMetaData*)metadata +{ + NBPhoneNumberDesc *generalNumberDesc = metadata.generalDesc; + + //NSLog(@"getNumberTypeHelper - UNKNOWN 1"); + if ([NBMetadataHelper hasValue:generalNumberDesc.nationalNumberPattern] == NO || + [self isNumberMatchingDesc:nationalNumber numberDesc:generalNumberDesc] == NO) + { + //NSLog(@"getNumberTypeHelper - UNKNOWN 2"); + return NBEPhoneNumberTypeUNKNOWN; + } + + //NSLog(@"getNumberTypeHelper - PREMIUM_RATE 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.premiumRate]) + { + //NSLog(@"getNumberTypeHelper - PREMIUM_RATE 2"); + return NBEPhoneNumberTypePREMIUM_RATE; + } + + //NSLog(@"getNumberTypeHelper - TOLL_FREE 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.tollFree]) + { + //NSLog(@"getNumberTypeHelper - TOLL_FREE 2"); + return NBEPhoneNumberTypeTOLL_FREE; + } + + //NSLog(@"getNumberTypeHelper - SHARED_COST 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.sharedCost]) + { + //NSLog(@"getNumberTypeHelper - SHARED_COST 2"); + return NBEPhoneNumberTypeSHARED_COST; + } + + //NSLog(@"getNumberTypeHelper - VOIP 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.voip]) + { + //NSLog(@"getNumberTypeHelper - VOIP 2"); + return NBEPhoneNumberTypeVOIP; + } + + //NSLog(@"getNumberTypeHelper - PERSONAL_NUMBER 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.personalNumber]) + { + //NSLog(@"getNumberTypeHelper - PERSONAL_NUMBER 2"); + return NBEPhoneNumberTypePERSONAL_NUMBER; + } + + //NSLog(@"getNumberTypeHelper - PAGER 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.pager]) + { + //NSLog(@"getNumberTypeHelper - PAGER 2"); + return NBEPhoneNumberTypePAGER; + } + + //NSLog(@"getNumberTypeHelper - UAN 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.uan]) + { + //NSLog(@"getNumberTypeHelper - UAN 2"); + return NBEPhoneNumberTypeUAN; + } + + //NSLog(@"getNumberTypeHelper - VOICEMAIL 1"); + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.voicemail]) + { + //NSLog(@"getNumberTypeHelper - VOICEMAIL 2"); + return NBEPhoneNumberTypeVOICEMAIL; + } + + if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.fixedLine]) + { + if (metadata.sameMobileAndFixedLinePattern) + { + //NSLog(@"getNumberTypeHelper - FIXED_LINE_OR_MOBILE"); + return NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE; + } + else if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.mobile]) + { + //NSLog(@"getNumberTypeHelper - FIXED_LINE_OR_MOBILE"); + return NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE; + } + //NSLog(@"getNumberTypeHelper - FIXED_LINE"); + return NBEPhoneNumberTypeFIXED_LINE; + } + + // Otherwise, test to see if the number is mobile. Only do this if certain + // that the patterns for mobile and fixed line aren't the same. + if ([metadata sameMobileAndFixedLinePattern] == NO && [self isNumberMatchingDesc:nationalNumber numberDesc:metadata.mobile]) { + return NBEPhoneNumberTypeMOBILE; + } + + return NBEPhoneNumberTypeUNKNOWN; +} + + +/** + * @param {string} nationalNumber + * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc + * @return {boolean} + * @private + */ +- (BOOL)isNumberMatchingDesc:(NSString *)nationalNumber numberDesc:(NBPhoneNumberDesc*)numberDesc +{ + if (numberDesc == nil) { + return NO; + } + + if ([NBMetadataHelper hasValue:numberDesc.possibleNumberPattern] == NO || [numberDesc.possibleNumberPattern isEqual:@"NA"]) { + return [self matchesEntirely:numberDesc.nationalNumberPattern string:nationalNumber]; + } + + if ([NBMetadataHelper hasValue:numberDesc.nationalNumberPattern] == NO || [numberDesc.nationalNumberPattern isEqual:@"NA"]) { + return [self matchesEntirely:numberDesc.possibleNumberPattern string:nationalNumber]; + } + + return [self matchesEntirely:numberDesc.possibleNumberPattern string:nationalNumber] && + [self matchesEntirely:numberDesc.nationalNumberPattern string:nationalNumber]; +} + + +/** + * Tests whether a phone number matches a valid pattern. Note this doesn't + * verify the number is actually in use, which is impossible to tell by just + * looking at a number itself. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want + * to validate. + * @return {boolean} a boolean that indicates whether the number is of a valid + * pattern. + */ +- (BOOL)isValidNumber:(NBPhoneNumber*)number +{ + NSString *regionCode = [self getRegionCodeForNumber:number]; + return [self isValidNumberForRegion:number regionCode:regionCode]; +} + + +/** + * Tests whether a phone number is valid for a certain region. Note this doesn't + * verify the number is actually in use, which is impossible to tell by just + * looking at a number itself. If the country calling code is not the same as + * the country calling code for the region, this immediately exits with NO. + * After this, the specific number pattern rules for the region are examined. + * This is useful for determining for example whether a particular number is + * valid for Canada, rather than just a valid NANPA number. + * Warning: In most cases, you want to use {@link #isValidNumber} instead. For + * example, this method will mark numbers from British Crown dependencies such + * as the Isle of Man as invalid for the region "GB" (United Kingdom), since it + * has its own region code, "IM", which may be undesirable. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want + * to validate. + * @param {?string} regionCode the region that we want to validate the phone + * number for. + * @return {boolean} a boolean that indicates whether the number is of a valid + * pattern. + */ +- (BOOL)isValidNumberForRegion:(NBPhoneNumber*)number regionCode:(NSString *)regionCode +{ + NSNumber *countryCode = [number.countryCode copy]; + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode]; + if (metadata == nil || + ([NB_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:regionCode] == NO && + ![countryCode isEqualToNumber:[self getCountryCodeForValidRegion:regionCode error:nil]])) { + // Either the region code was invalid, or the country calling code for this + // number does not match that of the region code. + return NO; + } + + NBPhoneNumberDesc *generalNumDesc = metadata.generalDesc; + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number]; + + // For regions where we don't have metadata for PhoneNumberDesc, we treat any + // number passed in as a valid number if its national significant number is + // between the minimum and maximum lengths defined by ITU for a national + // significant number. + + if ([NBMetadataHelper hasValue:generalNumDesc.nationalNumberPattern] == NO) { + unsigned int numberLength = (unsigned int)nationalSignificantNumber.length; + return numberLength > MIN_LENGTH_FOR_NSN_ && numberLength <= MAX_LENGTH_FOR_NSN_; + } + + return [self getNumberTypeHelper:nationalSignificantNumber metadata:metadata] != NBEPhoneNumberTypeUNKNOWN; +} + + +/** + * Returns the region where a phone number is from. This could be used for + * geocoding at the region level. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin + * we want to know. + * @return {?string} the region where the phone number is from, or nil + * if no region matches this calling code. + */ +- (NSString *)getRegionCodeForNumber:(NBPhoneNumber*)phoneNumber +{ + if (phoneNumber == nil) { + return nil; + } + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NSArray *regionCodes = [helper regionCodeFromCountryCode:phoneNumber.countryCode]; + if (regionCodes == nil || [regionCodes count] <= 0) { + return nil; + } + + if ([regionCodes count] == 1) { + return [regionCodes objectAtIndex:0]; + } else { + return [self getRegionCodeForNumberFromRegionList:phoneNumber regionCodes:regionCodes]; + } +} + + +/** + * @param {i18n.phonenumbers.PhoneNumber} number + * @param {Array.} regionCodes + * @return {?string} + * @private + + */ +- (NSString *)getRegionCodeForNumberFromRegionList:(NBPhoneNumber*)phoneNumber regionCodes:(NSArray*)regionCodes +{ + NSString *nationalNumber = [self getNationalSignificantNumber:phoneNumber]; + unsigned int regionCodesCount = (unsigned int)[regionCodes count]; + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + for (unsigned int i = 0; i} + */ +- (NSArray*)getRegionCodesForCountryCode:(NSNumber *)countryCallingCode +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NSArray *regionCodes = [helper regionCodeFromCountryCode:countryCallingCode]; + return regionCodes == nil ? nil : regionCodes; +} + + +/** + * Returns the country calling code for a specific region. For example, this + * would be 1 for the United States, and 64 for New Zealand. + * + * @param {?string} regionCode the region that we want to get the country + * calling code for. + * @return {number} the country calling code for the region denoted by + * regionCode. + */ +- (NSNumber*)getCountryCodeForRegion:(NSString *)regionCode +{ + if ([self isValidRegionCode:regionCode] == NO) { + return @0; + } + + NSError *error = nil; + NSNumber *res = [self getCountryCodeForValidRegion:regionCode error:&error]; + if (error != nil) { + return @0; + } + + return res; +} + + +/** + * Returns the country calling code for a specific region. For example, this + * would be 1 for the United States, and 64 for New Zealand. Assumes the region + * is already valid. + * + * @param {?string} regionCode the region that we want to get the country + * calling code for. + * @return {number} the country calling code for the region denoted by + * regionCode. + * @throws {string} if the region is invalid + * @private + */ +- (NSNumber*)getCountryCodeForValidRegion:(NSString *)regionCode error:(NSError**)error +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadata = [helper getMetadataForRegion:regionCode]; + + if (metadata == nil) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid region code:%@", regionCode] + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:@"INVALID_REGION_CODE" code:0 userInfo:userInfo]; + } + + return @-1; + } + + return metadata.countryCode; +} + + +/** + * Returns the national dialling prefix for a specific region. For example, this + * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits + * to NO to strip symbols like '~' (which indicates a wait for a dialling + * tone) from the prefix returned. If no national prefix is present, we return + * nil. + * + *

Warning: Do not use this method for do-your-own formatting - for some + * regions, the national dialling prefix is used only for certain types of + * numbers. Use the library's formatting functions to prefix the national prefix + * when required. + * + * @param {?string} regionCode the region that we want to get the dialling + * prefix for. + * @param {boolean} stripNonDigits NO to strip non-digits from the national + * dialling prefix. + * @return {?string} the dialling prefix for the region denoted by + * regionCode. + */ +- (NSString *)getNddPrefixForRegion:(NSString *)regionCode stripNonDigits:(BOOL)stripNonDigits +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadata = [helper getMetadataForRegion:regionCode]; + if (metadata == nil) { + return nil; + } + + NSString *nationalPrefix = metadata.nationalPrefix; + // If no national prefix was found, we return nil. + if (nationalPrefix.length == 0) { + return nil; + } + + if (stripNonDigits) { + // Note: if any other non-numeric symbols are ever used in national + // prefixes, these would have to be removed here as well. + nationalPrefix = [nationalPrefix stringByReplacingOccurrencesOfString:@"~" withString:@""]; + } + return nationalPrefix; +} + + +/** + * Checks if this is a region under the North American Numbering Plan + * Administration (NANPA). + * + * @param {?string} regionCode the ISO 3166-1 two-letter region code. + * @return {boolean} NO if regionCode is one of the regions under NANPA. + */ +- (BOOL)isNANPACountry:(NSString *)regionCode +{ + BOOL isExists = NO; + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NSArray *res = [helper regionCodeFromCountryCode:[NSNumber numberWithUnsignedInteger:NANPA_COUNTRY_CODE_]]; + + for (NSString *inRegionCode in res) { + if ([inRegionCode isEqualToString:regionCode.uppercaseString]) { + isExists = YES; + } + } + + return regionCode != nil && isExists; +} + + +/** + * Checks whether countryCode represents the country calling code from a region + * whose national significant number could contain a leading zero. An example of + * such a region is Italy. Returns NO if no metadata for the country is + * found. + * + * @param {number} countryCallingCode the country calling code. + * @return {boolean} + */ +- (BOOL)isLeadingZeroPossible:(NSNumber *)countryCallingCode +{ + NBPhoneMetaData *mainMetadataForCallingCode = [self getMetadataForRegionOrCallingCode:countryCallingCode + regionCode:[self getRegionCodeForCountryCode:countryCallingCode]]; + + return mainMetadataForCallingCode != nil && mainMetadataForCallingCode.leadingZeroPossible; +} + + +/** + * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. + * A valid vanity number will start with at least 3 digits and will have three + * or more alpha characters. This does not do region-specific checks - to work + * out if this number is actually valid for a region, it should be parsed and + * methods such as {@link #isPossibleNumberWithReason} and + * {@link #isValidNumber} should be used. + * + * @param {string} number the number that needs to be checked. + * @return {boolean} NO if the number is a valid vanity number. + */ +- (BOOL)isAlphaNumber:(NSString *)number +{ + if ([self isViablePhoneNumber:number] == NO) { + // Number is too short, or doesn't match the basic phone number pattern. + return NO; + } + + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + number = [helper normalizeNonBreakingSpace:number]; + + /** @type {!goog.string.StringBuffer} */ + NSString *strippedNumber = [number copy]; + [self maybeStripExtension:&strippedNumber]; + + return [self matchesEntirely:VALID_ALPHA_PHONE_PATTERN_STRING string:strippedNumber]; +} + + +/** + * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of + * returning the reason for failure, this method returns a boolean value. + * + * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be + * checked. + * @return {boolean} NO if the number is possible. + */ +- (BOOL)isPossibleNumber:(NBPhoneNumber*)number error:(NSError**)error +{ + BOOL res = NO; + @try { + res = [self isPossibleNumber:number]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + + +- (BOOL)isPossibleNumber:(NBPhoneNumber*)number +{ + return [self isPossibleNumberWithReason:number] == NBEValidationResultIS_POSSIBLE; +} + + +/** + * Helper method to check a number against a particular pattern and determine + * whether it matches, or is too short or too long. Currently, if a number + * pattern suggests that numbers of length 7 and 10 are possible, and a number + * in between these possible lengths is entered, such as of length 8, this will + * return TOO_LONG. + * + * @param {string} numberPattern + * @param {string} number + * @return {ValidationResult} + * @private + */ +- (NBEValidationResult)testNumberLengthAgainstPattern:(NSString *)numberPattern number:(NSString *)number +{ + if ([self matchesEntirely:numberPattern string:number]) { + return NBEValidationResultIS_POSSIBLE; + } + + if ([self stringPositionByRegex:number regex:numberPattern] == 0) { + return NBEValidationResultTOO_LONG; + } else { + return NBEValidationResultTOO_SHORT; + } +} + + +/** + * Check whether a phone number is a possible number. It provides a more lenient + * check than {@link #isValidNumber} in the following sense: + *

    + *
  1. It only checks the length of phone numbers. In particular, it doesn't + * check starting digits of the number. + *
  2. It doesn't attempt to figure out the type of the number, but uses general + * rules which applies to all types of phone numbers in a region. Therefore, it + * is much faster than isValidNumber. + *
  3. For fixed line numbers, many regions have the concept of area code, which + * together with subscriber number constitute the national significant number. + * It is sometimes okay to dial the subscriber number only when dialing in the + * same area. This function will return NO if the subscriber-number-only + * version is passed in. On the other hand, because isValidNumber validates + * using information on both starting digits (for fixed line numbers, that would + * most likely be area codes) and length (obviously includes the length of area + * codes for fixed line numbers), it will return NO for the + * subscriber-number-only version. + *
+ * + * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be + * checked. + * @return {ValidationResult} a + * ValidationResult object which indicates whether the number is possible. + */ +- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number error:(NSError *__autoreleasing *)error +{ + NBEValidationResult res = NBEValidationResultUNKNOWN; + @try { + res = [self isPossibleNumberWithReason:number]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + + return res; +} + + +- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number +{ + NSString *nationalNumber = [self getNationalSignificantNumber:number]; + NSNumber *countryCode = number.countryCode; + // Note: For Russian Fed and NANPA numbers, we just use the rules from the + // default region (US or Russia) since the getRegionCodeForNumber will not + // work if the number is possible but not valid. This would need to be + // revisited if the possible number pattern ever differed between various + // regions within those plans. + if ([self hasValidCountryCallingCode:countryCode] == NO) { + return NBEValidationResultINVALID_COUNTRY_CODE; + } + + NSString *regionCode = [self getRegionCodeForCountryCode:countryCode]; + // Metadata cannot be nil because the country calling code is valid. + NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode]; + NBPhoneNumberDesc *generalNumDesc = metadata.generalDesc; + + // Handling case of numbers with no metadata. + if ([NBMetadataHelper hasValue:generalNumDesc.nationalNumberPattern] == NO) { + unsigned int numberLength = (unsigned int)nationalNumber.length; + + if (numberLength < MIN_LENGTH_FOR_NSN_) { + return NBEValidationResultTOO_SHORT; + } else if (numberLength > MAX_LENGTH_FOR_NSN_) { + return NBEValidationResultTOO_LONG; + } else { + return NBEValidationResultIS_POSSIBLE; + } + } + + NSString *possibleNumberPattern = generalNumDesc.possibleNumberPattern; + return [self testNumberLengthAgainstPattern:possibleNumberPattern number:nationalNumber]; +} + + +/** + * Check whether a phone number is a possible number given a number in the form + * of a string, and the region where the number could be dialed from. It + * provides a more lenient check than {@link #isValidNumber}. See + * {@link #isPossibleNumber} for details. + * + *

This method first parses the number, then invokes + * {@link #isPossibleNumber} with the resultant PhoneNumber object. + * + * @param {string} number the number that needs to be checked, in the form of a + * string. + * @param {string} regionDialingFrom the region that we are expecting the number + * to be dialed from. + * Note this is different from the region where the number belongs. + * For example, the number +1 650 253 0000 is a number that belongs to US. + * When written in this form, it can be dialed from any region. When it is + * written as 00 1 650 253 0000, it can be dialed from any region which uses + * an international dialling prefix of 00. When it is written as + * 650 253 0000, it can only be dialed from within the US, and when written + * as 253 0000, it can only be dialed from within a smaller area in the US + * (Mountain View, CA, to be more specific). + * @return {boolean} NO if the number is possible. + */ +- (BOOL)isPossibleNumberString:(NSString *)number regionDialingFrom:(NSString *)regionDialingFrom error:(NSError**)error +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + number = [helper normalizeNonBreakingSpace:number]; + + BOOL res = [self isPossibleNumber:[self parse:number defaultRegion:regionDialingFrom error:error]]; + return res; +} + +/** + * Attempts to extract a valid number from a phone number that is too long to be + * valid, and resets the PhoneNumber object passed in to that valid version. If + * no valid number could be extracted, the PhoneNumber object passed in will not + * be modified. + * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which + * contains a number that is too long to be valid. + * @return {boolean} NO if a valid phone number can be successfully extracted. + */ + +- (BOOL)truncateTooLongNumber:(NBPhoneNumber*)number +{ + if ([self isValidNumber:number]) { + return YES; + } + + NBPhoneNumber *numberCopy = [number copy]; + NSNumber *nationalNumber = number.nationalNumber; + do { + nationalNumber = [NSNumber numberWithLongLong:(long long)floor(nationalNumber.unsignedLongLongValue / 10)]; + numberCopy.nationalNumber = [nationalNumber copy]; + if ([nationalNumber isEqualToNumber:@0] || [self isPossibleNumberWithReason:numberCopy] == NBEValidationResultTOO_SHORT) { + return NO; + } + } + while ([self isValidNumber:numberCopy] == NO); + + number.nationalNumber = nationalNumber; + return YES; +} + + +/** + * Extracts country calling code from fullNumber, returns it and places the + * remaining number in nationalNumber. It assumes that the leading plus sign or + * IDD has already been removed. Returns 0 if fullNumber doesn't start with a + * valid country calling code, and leaves nationalNumber unmodified. + * + * @param {!goog.string.StringBuffer} fullNumber + * @param {!goog.string.StringBuffer} nationalNumber + * @return {number} + */ +- (NSNumber *)extractCountryCode:(NSString *)fullNumber nationalNumber:(NSString **)nationalNumber +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + fullNumber = [helper normalizeNonBreakingSpace:fullNumber]; + + if ((fullNumber.length == 0) || ([[fullNumber substringToIndex:1] isEqualToString:@"0"])) { + // Country codes do not begin with a '0'. + return @0; + } + + unsigned int numberLength = (unsigned int)fullNumber.length; + unsigned int maxCountryCode = MAX_LENGTH_COUNTRY_CODE_; + + if ([fullNumber hasPrefix:@"+"]) { + maxCountryCode = MAX_LENGTH_COUNTRY_CODE_ + 1; + } + + for (unsigned int i = 1; i <= maxCountryCode && i <= numberLength; ++i) { + NSString *subNumber = [fullNumber substringWithRange:NSMakeRange(0, i)]; + NSNumber *potentialCountryCode = [NSNumber numberWithInteger:[subNumber integerValue]]; + + NSArray *regionCodes = [helper regionCodeFromCountryCode:potentialCountryCode]; + if (regionCodes != nil && regionCodes.count > 0) { + if (nationalNumber != NULL) { + if ((*nationalNumber) == nil) { + (*nationalNumber) = [NSString stringWithFormat:@"%@", [fullNumber substringFromIndex:i]]; + } else { + (*nationalNumber) = [NSString stringWithFormat:@"%@%@", (*nationalNumber), [fullNumber substringFromIndex:i]]; + } + } + return potentialCountryCode; + } + } + + return @0; +} + + +/** + * Convenience method to get a list of what regions the library has metadata + * for. + * @return {!Array.} region codes supported by the library. + */ + +- (NSArray *)getSupportedRegions +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NSArray *allKeys = [[helper CCode2CNMap] allKeys]; + NSPredicate *predicateIsNaN = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [self isNaN:evaluatedObject]; + }]; + + NSArray *supportedRegions = [allKeys filteredArrayUsingPredicate:predicateIsNaN]; + return supportedRegions; +} + +/* + i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedRegions = function() { + return goog.array.filter( + Object.keys(i18n.phonenumbers.metadata.countryToMetadata), + function(regionCode) { + return isNaN(regionCode); + }); + }; + */ + +/** + * Convenience method to get a list of what global network calling codes the + * library has metadata for. + * @return {!Array.} global network calling codes supported by the + * library. + */ +/* + i18n.phonenumbers.PhoneNumberUtil.prototype. + getSupportedGlobalNetworkCallingCodes = function() { + var callingCodesAsStrings = goog.array.filter( + Object.keys(i18n.phonenumbers.metadata.countryToMetadata), + function(regionCode) { + return !isNaN(regionCode); + }); + return goog.array.map(callingCodesAsStrings, + function(callingCode) { + return parseInt(callingCode, 10); + }); + }; + */ + + +/** + * Tries to extract a country calling code from a number. This method will + * return zero if no country calling code is considered to be present. Country + * calling codes are extracted in the following ways: + *

    + *
  • by stripping the international dialing prefix of the region the person is + * dialing from, if this is present in the number, and looking at the next + * digits + *
  • by stripping the '+' sign if present and then looking at the next digits + *
  • by comparing the start of the number and the country calling code of the + * default region. If the number is not considered possible for the numbering + * plan of the default region initially, but starts with the country calling + * code of this region, validation will be reattempted after stripping this + * country calling code. If this number is considered a possible number, then + * the first digits will be considered the country calling code and removed as + * such. + *
+ * + * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but + * the country calling code supplied after this does not match that of any known + * region. + * + * @param {string} number non-normalized telephone number that we wish to + * extract a country calling code from - may begin with '+'. + * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata + * about the region this number may be from. + * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store + * the national significant number in, in the case that a country calling + * code was extracted. The number is appended to any existing contents. If + * no country calling code was extracted, this will be left unchanged. + * @param {boolean} keepRawInput NO if the country_code_source and + * preferred_carrier_code fields of phoneNumber should be populated. + * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object + * where the country_code and country_code_source need to be populated. + * Note the country_code is always populated, whereas country_code_source is + * only populated when keepCountryCodeSource is NO. + * @return {number} the country calling code extracted or 0 if none could be + * extracted. + * @throws {i18n.phonenumbers.Error} + */ +- (NSNumber *)maybeExtractCountryCode:(NSString *)number metadata:(NBPhoneMetaData*)defaultRegionMetadata + nationalNumber:(NSString **)nationalNumber keepRawInput:(BOOL)keepRawInput + phoneNumber:(NBPhoneNumber**)phoneNumber error:(NSError**)error +{ + if (nationalNumber == NULL || phoneNumber == NULL || number.length <= 0) { + return @0; + } + + NSString *fullNumber = [number copy]; + // Set the default prefix to be something that will never match. + NSString *possibleCountryIddPrefix = @""; + if (defaultRegionMetadata != nil) { + possibleCountryIddPrefix = defaultRegionMetadata.internationalPrefix; + } + + if (possibleCountryIddPrefix == nil) { + possibleCountryIddPrefix = @"NonMatch"; + } + + /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */ + NBECountryCodeSource countryCodeSource = [self maybeStripInternationalPrefixAndNormalize:&fullNumber + possibleIddPrefix:possibleCountryIddPrefix]; + if (keepRawInput) { + (*phoneNumber).countryCodeSource = [NSNumber numberWithInteger:countryCodeSource]; + } + + if (countryCodeSource != NBECountryCodeSourceFROM_DEFAULT_COUNTRY) { + if (fullNumber.length <= MIN_LENGTH_FOR_NSN_) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"TOO_SHORT_AFTER_IDD:%@", fullNumber] + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:@"TOO_SHORT_AFTER_IDD" code:0 userInfo:userInfo]; + } + return @0; + } + + NSNumber *potentialCountryCode = [self extractCountryCode:fullNumber nationalNumber:nationalNumber]; + + if (![potentialCountryCode isEqualToNumber:@0]) { + (*phoneNumber).countryCode = potentialCountryCode; + return potentialCountryCode; + } + + // If this fails, they must be using a strange country calling code that we + // don't recognize, or that doesn't exist. + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"INVALID_COUNTRY_CODE:%@", potentialCountryCode] + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:@"INVALID_COUNTRY_CODE" code:0 userInfo:userInfo]; + } + + return @0; + } else if (defaultRegionMetadata != nil) { + // Check to see if the number starts with the country calling code for the + // default region. If so, we remove the country calling code, and do some + // checks on the validity of the number before and after. + NSNumber *defaultCountryCode = defaultRegionMetadata.countryCode; + NSString *defaultCountryCodeString = [NSString stringWithFormat:@"%@", defaultCountryCode]; + NSString *normalizedNumber = [fullNumber copy]; + + if ([normalizedNumber hasPrefix:defaultCountryCodeString]) { + NSString *potentialNationalNumber = [normalizedNumber substringFromIndex:defaultCountryCodeString.length]; + NBPhoneNumberDesc *generalDesc = defaultRegionMetadata.generalDesc; + + NSString *validNumberPattern = generalDesc.nationalNumberPattern; + // Passing null since we don't need the carrier code. + [self maybeStripNationalPrefixAndCarrierCode:&potentialNationalNumber metadata:defaultRegionMetadata carrierCode:nil]; + + NSString *potentialNationalNumberStr = [potentialNationalNumber copy]; + NSString *possibleNumberPattern = generalDesc.possibleNumberPattern; + // If the number was not valid before but is valid now, or if it was too + // long before, we consider the number with the country calling code + // stripped to be a better result and keep that instead. + if ((![self matchesEntirely:validNumberPattern string:fullNumber] && + [self matchesEntirely:validNumberPattern string:potentialNationalNumberStr]) || + [self testNumberLengthAgainstPattern:possibleNumberPattern number:fullNumber] == NBEValidationResultTOO_LONG) { + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:potentialNationalNumberStr]; + if (keepRawInput) { + (*phoneNumber).countryCodeSource = [NSNumber numberWithInteger:NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN]; + } + (*phoneNumber).countryCode = defaultCountryCode; + return defaultCountryCode; + } + } + } + // No country calling code present. + (*phoneNumber).countryCode = @0; + return @0; +} + + +/** + * Strips the IDD from the start of the number if present. Helper function used + * by maybeStripInternationalPrefixAndNormalize. + * + * @param {!RegExp} iddPattern the regular expression for the international + * prefix. + * @param {!goog.string.StringBuffer} number the phone number that we wish to + * strip any international dialing prefix from. + * @return {boolean} NO if an international prefix was present. + * @private + */ +- (BOOL)parsePrefixAsIdd:(NSString *)iddPattern sourceString:(NSString **)number +{ + if (number == NULL) { + return NO; + } + + NSString *numberStr = [(*number) copy]; + + if ([self stringPositionByRegex:numberStr regex:iddPattern] == 0) { + NSTextCheckingResult *matched = [[self matchesByRegex:numberStr regex:iddPattern] objectAtIndex:0]; + NSString *matchedString = [numberStr substringWithRange:matched.range]; + unsigned int matchEnd = (unsigned int)matchedString.length; + NSString *remainString = [numberStr substringFromIndex:matchEnd]; + + NSArray *matchedGroups = [_CAPTURING_DIGIT_PATTERN matchesInString:remainString options:0 range:NSMakeRange(0, remainString.length)]; + + if (matchedGroups && [matchedGroups count] > 0 && [matchedGroups objectAtIndex:0] != nil) { + NSString *digitMatched = [remainString substringWithRange:((NSTextCheckingResult*)[matchedGroups objectAtIndex:0]).range]; + if (digitMatched.length > 0) { + NSString *normalizedGroup = [self normalizeDigitsOnly:digitMatched]; + if ([normalizedGroup isEqualToString:@"0"]) { + return NO; + } + } + } + + (*number) = [remainString copy]; + return YES; + } + + return NO; +} + + +/** + * Strips any international prefix (such as +, 00, 011) present in the number + * provided, normalizes the resulting number, and indicates if an international + * prefix was present. + * + * @param {!goog.string.StringBuffer} number the non-normalized telephone number + * that we wish to strip any international dialing prefix from. + * @param {string} possibleIddPrefix the international direct dialing prefix + * from the region we think this number may be dialed in. + * @return {CountryCodeSource} the corresponding + * CountryCodeSource if an international dialing prefix could be removed + * from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if + * the number did not seem to be in international format. + */ +- (NBECountryCodeSource)maybeStripInternationalPrefixAndNormalize:(NSString **)numberStr possibleIddPrefix:(NSString *)possibleIddPrefix +{ + if (numberStr == NULL || (*numberStr).length == 0) { + return NBECountryCodeSourceFROM_DEFAULT_COUNTRY; + } + + // Check to see if the number begins with one or more plus signs. + if ([self isStartingStringByRegex:(*numberStr) regex:LEADING_PLUS_CHARS_PATTERN]) { + (*numberStr) = [self replaceStringByRegex:(*numberStr) regex:LEADING_PLUS_CHARS_PATTERN withTemplate:@""]; + // Can now normalize the rest of the number since we've consumed the '+' + // sign at the start. + (*numberStr) = [self normalizePhoneNumber:(*numberStr)]; + return NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN; + } + + // Attempt to parse the first digits as an international prefix. + NSString *iddPattern = [possibleIddPrefix copy]; + [self normalizeSB:numberStr]; + + return [self parsePrefixAsIdd:iddPattern sourceString:numberStr] ? NBECountryCodeSourceFROM_NUMBER_WITH_IDD : NBECountryCodeSourceFROM_DEFAULT_COUNTRY; +} + + +/** + * Strips any national prefix (such as 0, 1) present in the number provided. + * + * @param {!goog.string.StringBuffer} number the normalized telephone number + * that we wish to strip any national dialing prefix from. + * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the + * region that we think this number is from. + * @param {goog.string.StringBuffer} carrierCode a place to insert the carrier + * code if one is extracted. + * @return {boolean} NO if a national prefix or carrier code (or both) could + * be extracted. + */ +- (BOOL)maybeStripNationalPrefixAndCarrierCode:(NSString **)number metadata:(NBPhoneMetaData*)metadata carrierCode:(NSString **)carrierCode +{ + if (number == NULL) { + return NO; + } + + NSString *numberStr = [(*number) copy]; + unsigned int numberLength = (unsigned int)numberStr.length; + NSString *possibleNationalPrefix = metadata.nationalPrefixForParsing; + + if (numberLength == 0 || [NBMetadataHelper hasValue:possibleNationalPrefix] == NO) { + // Early return for numbers of zero length. + return NO; + } + + // Attempt to parse the first digits as a national prefix. + NSString *prefixPattern = [NSString stringWithFormat:@"^(?:%@)", possibleNationalPrefix]; + NSError *error = nil; + NSRegularExpression *currentPattern = [self regularExpressionWithPattern:prefixPattern options:0 error:&error]; + + NSArray *prefixMatcher = [currentPattern matchesInString:numberStr options:0 range:NSMakeRange(0, numberLength)]; + if (prefixMatcher && [prefixMatcher count] > 0) { + NSString *nationalNumberRule = metadata.generalDesc.nationalNumberPattern; + NSTextCheckingResult *firstMatch = [prefixMatcher objectAtIndex:0]; + NSString *firstMatchString = [numberStr substringWithRange:firstMatch.range]; + + // prefixMatcher[numOfGroups] == null implies nothing was captured by the + // capturing groups in possibleNationalPrefix; therefore, no transformation + // is necessary, and we just remove the national prefix. + unsigned int numOfGroups = (unsigned int)firstMatch.numberOfRanges - 1; + NSString *transformRule = metadata.nationalPrefixTransformRule; + NSString *transformedNumber = @""; + NSRange firstRange = [firstMatch rangeAtIndex:numOfGroups]; + NSString *firstMatchStringWithGroup = (firstRange.location != NSNotFound && firstRange.location < numberStr.length) ? [numberStr substringWithRange:firstRange] : nil; + BOOL noTransform = (transformRule == nil || transformRule.length == 0 || [NBMetadataHelper hasValue:firstMatchStringWithGroup] == NO); + + if (noTransform) { + transformedNumber = [numberStr substringFromIndex:firstMatchString.length]; + } else { + transformedNumber = [self replaceFirstStringByRegex:numberStr regex:prefixPattern withTemplate:transformRule]; + } + // If the original number was viable, and the resultant number is not, + // we return. + if ([NBMetadataHelper hasValue:nationalNumberRule ] && [self matchesEntirely:nationalNumberRule string:numberStr] && + [self matchesEntirely:nationalNumberRule string:transformedNumber] == NO) { + return NO; + } + + if ((noTransform && numOfGroups > 0 && [NBMetadataHelper hasValue:firstMatchStringWithGroup]) || (!noTransform && numOfGroups > 1)) { + if (carrierCode != NULL && (*carrierCode) != nil) { + (*carrierCode) = [(*carrierCode) stringByAppendingString:firstMatchStringWithGroup]; + } + } else if ((noTransform && numOfGroups > 0 && [NBMetadataHelper hasValue:firstMatchString]) || (!noTransform && numOfGroups > 1)) { + if (carrierCode != NULL && (*carrierCode) != nil) { + (*carrierCode) = [(*carrierCode) stringByAppendingString:firstMatchString]; + } + } + + (*number) = transformedNumber; + return YES; + } + return NO; +} + + +/** + * Strips any extension (as in, the part of the number dialled after the call is + * connected, usually indicated with extn, ext, x or similar) from the end of + * the number, and returns it. + * + * @param {!goog.string.StringBuffer} number the non-normalized telephone number + * that we wish to strip the extension from. + * @return {string} the phone extension. + */ +- (NSString *)maybeStripExtension:(NSString **)number +{ + if (number == NULL) { + return @""; + } + + NSString *numberStr = [(*number) copy]; + int mStart = [self stringPositionByRegex:numberStr regex:EXTN_PATTERN]; + + // If we find a potential extension, and the number preceding this is a viable + // number, we assume it is an extension. + if (mStart >= 0 && [self isViablePhoneNumber:[numberStr substringWithRange:NSMakeRange(0, mStart)]]) { + // The numbers are captured into groups in the regular expression. + NSTextCheckingResult *firstMatch = [self matcheFirstByRegex:numberStr regex:EXTN_PATTERN]; + unsigned int matchedGroupsLength = (unsigned int)[firstMatch numberOfRanges]; + + for (unsigned int i=1; i 0 && [self isStartingStringByRegex:numberToParse regex:LEADING_PLUS_CHARS_PATTERN]); +} + + +/** + * Parses a string and returns it in proto buffer format. This method will throw + * a {@link i18n.phonenumbers.Error} if the number is not considered to be a + * possible number. Note that validation of whether the number is actually a + * valid number for a particular region is not performed. This can be done + * separately with {@link #isValidNumber}. + * + * @param {?string} numberToParse number that we are attempting to parse. This + * can contain formatting such as +, ( and -, as well as a phone number + * extension. It can also be provided in RFC3966 format. + * @param {?string} defaultRegion region that we are expecting the number to be + * from. This is only used if the number being parsed is not written in + * international format. The country_code for the number in this case would + * be stored as that of the default region supplied. If the number is + * guaranteed to start with a '+' followed by the country calling code, then + * 'ZZ' or nil can be supplied. + * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled + * with the parsed number. + * @throws {i18n.phonenumbers.Error} if the string is not considered to be a + * viable phone number or if no default region was supplied and the number + * is not in international format (does not start with +). + */ +- (NBPhoneNumber*)parse:(NSString *)numberToParse defaultRegion:(NSString *)defaultRegion error:(NSError**)error +{ + NSError *anError = nil; + NBPhoneNumber *phoneNumber = [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:NO checkRegion:YES error:&anError]; + + if (anError != nil) { + if (error != NULL) { + (*error) = [self errorWithObject:anError.description withDomain:anError.domain]; + } + } + return phoneNumber; +} + +/** + * Parses a string using the phone's carrier region (when available, ZZ otherwise). + * This uses the country the sim card in the phone is registered with. + * For example if you have an AT&T sim card but are in Europe, this will parse the + * number using +1 (AT&T is a US Carrier) as the default country code. + * This also works for CDMA phones which don't have a sim card. + */ +- (NBPhoneNumber*)parseWithPhoneCarrierRegion:(NSString *)numberToParse error:(NSError**)error +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + + numberToParse = [helper normalizeNonBreakingSpace:numberToParse]; + + NSString *defaultRegion = nil; +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH + defaultRegion = [self countryCodeByCarrier]; +#else + defaultRegion = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode]; +#endif + if ([NB_UNKNOWN_REGION isEqualToString:defaultRegion]) { + // get region from device as a failover (e.g. iPad) + NSLocale *currentLocale = [NSLocale currentLocale]; + defaultRegion = [currentLocale objectForKey:NSLocaleCountryCode]; + } + + return [self parse:numberToParse defaultRegion:defaultRegion error:error]; +} + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH + +static CTTelephonyNetworkInfo* _telephonyNetworkInfo; + +- (CTTelephonyNetworkInfo*)telephonyNetworkInfo{ + + // cache telephony network info; + // CTTelephonyNetworkInfo objects are unnecessarily created for every call to parseWithPhoneCarrierRegion:error: + // when in reality this information not change while an app lives in memory + // real-world performance test while parsing 93 phone numbers: + // before change: 126ms + // after change: 32ms + // using static instance prevents deallocation crashes due to ios bug + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _telephonyNetworkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + + return _telephonyNetworkInfo; + +} + +- (NSString *)countryCodeByCarrier +{ + + NSString *isoCode = [[self.telephonyNetworkInfo subscriberCellularProvider] isoCountryCode]; + + // The 2nd part of the if is working around an iOS 7 bug + // If the SIM card is missing, iOS 7 returns an empty string instead of nil + if (!isoCode || [isoCode isEqualToString:@""]) { + isoCode = NB_UNKNOWN_REGION; + } + + return isoCode; +} + +#endif + + +/** + * Parses a string and returns it in proto buffer format. This method differs + * from {@link #parse} in that it always populates the raw_input field of the + * protocol buffer with numberToParse as well as the country_code_source field. + * + * @param {string} numberToParse number that we are attempting to parse. This + * can contain formatting such as +, ( and -, as well as a phone number + * extension. + * @param {?string} defaultRegion region that we are expecting the number to be + * from. This is only used if the number being parsed is not written in + * international format. The country calling code for the number in this + * case would be stored as that of the default region supplied. + * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled + * with the parsed number. + * @throws {i18n.phonenumbers.Error} if the string is not considered to be a + * viable phone number or if no default region was supplied. + */ +- (NBPhoneNumber*)parseAndKeepRawInput:(NSString *)numberToParse defaultRegion:(NSString *)defaultRegion error:(NSError**)error +{ + if ([self isValidRegionCode:defaultRegion] == NO) { + if (numberToParse.length > 0 && [numberToParse hasPrefix:@"+"] == NO) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid country code:%@", numberToParse] + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:@"INVALID_COUNTRY_CODE" code:0 userInfo:userInfo]; + } + } + } + return [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:YES checkRegion:YES error:error]; +} + + +/** + * Parses a string and returns it in proto buffer format. This method is the + * same as the public {@link #parse} method, with the exception that it allows + * the default region to be nil, for use by {@link #isNumberMatch}. + * + * @param {?string} numberToParse number that we are attempting to parse. This + * can contain formatting such as +, ( and -, as well as a phone number + * extension. + * @param {?string} defaultRegion region that we are expecting the number to be + * from. This is only used if the number being parsed is not written in + * international format. The country calling code for the number in this + * case would be stored as that of the default region supplied. + * @param {boolean} keepRawInput whether to populate the raw_input field of the + * phoneNumber with numberToParse. + * @param {boolean} checkRegion should be set to NO if it is permitted for + * the default coregion to be nil or unknown ('ZZ'). + * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled + * with the parsed number. + * @throws {i18n.phonenumbers.Error} + * @private + */ +- (NBPhoneNumber*)parseHelper:(NSString *)numberToParse defaultRegion:(NSString *)defaultRegion + keepRawInput:(BOOL)keepRawInput checkRegion:(BOOL)checkRegion error:(NSError**)error +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + numberToParse = [helper normalizeNonBreakingSpace:numberToParse]; + + if (numberToParse == nil) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"NOT_A_NUMBER:%@", numberToParse] withDomain:@"NOT_A_NUMBER"]; + } + + return nil; + } else if (numberToParse.length > MAX_INPUT_STRING_LENGTH_) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"TOO_LONG:%@", numberToParse] withDomain:@"TOO_LONG"]; + } + + return nil; + } + + NSString *nationalNumber = @""; + [self buildNationalNumberForParsing:numberToParse nationalNumber:&nationalNumber]; + + if ([self isViablePhoneNumber:nationalNumber] == NO) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"NOT_A_NUMBER:%@", nationalNumber] withDomain:@"NOT_A_NUMBER"]; + } + + return nil; + } + + // Check the region supplied is valid, or that the extracted number starts + // with some sort of + sign so the number's region can be determined. + if (checkRegion && [self checkRegionForParsing:nationalNumber defaultRegion:defaultRegion] == NO) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"INVALID_COUNTRY_CODE:%@", defaultRegion] + withDomain:@"INVALID_COUNTRY_CODE"]; + } + + return nil; + } + + NBPhoneNumber *phoneNumber = [[NBPhoneNumber alloc] init]; + if (keepRawInput) { + phoneNumber.rawInput = [numberToParse copy]; + } + + // Attempt to parse extension first, since it doesn't require region-specific + // data and we want to have the non-normalised number here. + NSString *extension = [self maybeStripExtension:&nationalNumber]; + if (extension.length > 0) { + phoneNumber.extension = [extension copy]; + } + + NBPhoneMetaData *regionMetadata = [helper getMetadataForRegion:defaultRegion]; + // Check to see if the number is given in international format so we know + // whether this number is from the default region or not. + NSString *normalizedNationalNumber = @""; + NSNumber *countryCode = nil; + NSString *nationalNumberStr = [nationalNumber copy]; + + { + NSError *anError = nil; + countryCode = [self maybeExtractCountryCode:nationalNumberStr + metadata:regionMetadata + nationalNumber:&normalizedNationalNumber + keepRawInput:keepRawInput + phoneNumber:&phoneNumber error:&anError]; + + if (anError != nil) { + if ([anError.domain isEqualToString:@"INVALID_COUNTRY_CODE"] && [self stringPositionByRegex:nationalNumberStr + regex:LEADING_PLUS_CHARS_PATTERN] >= 0) + { + // Strip the plus-char, and try again. + NSError *aNestedError = nil; + nationalNumberStr = [self replaceStringByRegex:nationalNumberStr regex:LEADING_PLUS_CHARS_PATTERN withTemplate:@""]; + countryCode = [self maybeExtractCountryCode:nationalNumberStr + metadata:regionMetadata + nationalNumber:&normalizedNationalNumber + keepRawInput:keepRawInput + phoneNumber:&phoneNumber error:&aNestedError]; + if ([countryCode isEqualToNumber:@0]) { + if (error != NULL) + (*error) = [self errorWithObject:anError.description withDomain:anError.domain]; + + return nil; + } + } else { + if (error != NULL) + (*error) = [self errorWithObject:anError.description withDomain:anError.domain]; + + return nil; + } + } + } + + if (![countryCode isEqualToNumber:@0]) { + NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCode]; + if (phoneNumberRegion != defaultRegion) { + // Metadata cannot be nil because the country calling code is valid. + regionMetadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:phoneNumberRegion]; + } + } else { + // If no extracted country calling code, use the region supplied instead. + // The national number is just the normalized version of the number we were + // given to parse. + [self normalizeSB:&nationalNumber]; + normalizedNationalNumber = [normalizedNationalNumber stringByAppendingString:nationalNumber]; + + if (defaultRegion != nil) { + countryCode = regionMetadata.countryCode; + phoneNumber.countryCode = countryCode; + } else if (keepRawInput) { + [phoneNumber clearCountryCodeSource]; + } + } + + if (normalizedNationalNumber.length < MIN_LENGTH_FOR_NSN_){ + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"TOO_SHORT_NSN:%@", normalizedNationalNumber] withDomain:@"TOO_SHORT_NSN"]; + } + + return nil; + } + + if (regionMetadata != nil) { + NSString *carrierCode = @""; + [self maybeStripNationalPrefixAndCarrierCode:&normalizedNationalNumber metadata:regionMetadata carrierCode:&carrierCode]; + + if (keepRawInput) { + phoneNumber.preferredDomesticCarrierCode = [carrierCode copy]; + } + } + + NSString *normalizedNationalNumberStr = [normalizedNationalNumber copy]; + + unsigned int lengthOfNationalNumber = (unsigned int)normalizedNationalNumberStr.length; + if (lengthOfNationalNumber < MIN_LENGTH_FOR_NSN_) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"TOO_SHORT_NSN:%@", normalizedNationalNumber] withDomain:@"TOO_SHORT_NSN"]; + } + + return nil; + } + + if (lengthOfNationalNumber > MAX_LENGTH_FOR_NSN_) { + if (error != NULL) { + (*error) = [self errorWithObject:[NSString stringWithFormat:@"TOO_LONG:%@", normalizedNationalNumber] withDomain:@"TOO_LONG"]; + } + + return nil; + } + + if ([normalizedNationalNumberStr hasPrefix:@"0"]) { + phoneNumber.italianLeadingZero = YES; + } + + phoneNumber.nationalNumber = [NSNumber numberWithLongLong:[normalizedNationalNumberStr longLongValue]]; + return phoneNumber; +} + + +/** + * Converts numberToParse to a form that we can parse and write it to + * nationalNumber if it is written in RFC3966; otherwise extract a possible + * number out of it and write to nationalNumber. + * + * @param {?string} numberToParse number that we are attempting to parse. This + * can contain formatting such as +, ( and -, as well as a phone number + * extension. + * @param {!goog.string.StringBuffer} nationalNumber a string buffer for storing + * the national significant number. + * @private + */ +- (void)buildNationalNumberForParsing:(NSString *)numberToParse nationalNumber:(NSString **)nationalNumber +{ + if (nationalNumber == NULL) + return; + + int indexOfPhoneContext = [self indexOfStringByString:numberToParse target:RFC3966_PHONE_CONTEXT]; + if (indexOfPhoneContext > 0) + { + unsigned int phoneContextStart = indexOfPhoneContext + (unsigned int)RFC3966_PHONE_CONTEXT.length; + // If the phone context contains a phone number prefix, we need to capture + // it, whereas domains will be ignored. + if ([numberToParse characterAtIndex:phoneContextStart] == '+') + { + // Additional parameters might follow the phone context. If so, we will + // remove them here because the parameters after phone context are not + // important for parsing the phone number. + NSRange foundRange = [numberToParse rangeOfString:@";" options:NSLiteralSearch range:NSMakeRange(phoneContextStart, numberToParse.length - phoneContextStart)]; + if (foundRange.location != NSNotFound) + { + NSRange subRange = NSMakeRange(phoneContextStart, foundRange.location - phoneContextStart); + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[numberToParse substringWithRange:subRange]]; + } + else + { + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[numberToParse substringFromIndex:phoneContextStart]]; + } + } + + // Now append everything between the "tel:" prefix and the phone-context. + // This should include the national number, an optional extension or + // isdn-subaddress component. + unsigned int rfc3966Start = [self indexOfStringByString:numberToParse target:RFC3966_PREFIX] + (unsigned int)RFC3966_PREFIX.length; + NSString *subString = [numberToParse substringWithRange:NSMakeRange(rfc3966Start, indexOfPhoneContext - rfc3966Start)]; + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:subString]; + } + else + { + // Extract a possible number from the string passed in (this strips leading + // characters that could not be the start of a phone number.) + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[self extractPossibleNumber:numberToParse]]; + } + + // Delete the isdn-subaddress and everything after it if it is present. + // Note extension won't appear at the same time with isdn-subaddress + // according to paragraph 5.3 of the RFC3966 spec, + NSString *nationalNumberStr = [(*nationalNumber) copy]; + int indexOfIsdn = [self indexOfStringByString:nationalNumberStr target:RFC3966_ISDN_SUBADDRESS]; + if (indexOfIsdn > 0) + { + (*nationalNumber) = @""; + (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[nationalNumberStr substringWithRange:NSMakeRange(0, indexOfIsdn)]]; + } + // If both phone context and isdn-subaddress are absent but other + // parameters are present, the parameters are left in nationalNumber. This + // is because we are concerned about deleting content from a potential + // number string when there is no strong evidence that the number is + // actually written in RFC3966. +} + + +/** + * Takes two phone numbers and compares them for equality. + * + *

Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero + * for Italian numbers and any extension present are the same. Returns NSN_MATCH + * if either or both has no region specified, and the NSNs and extensions are + * the same. Returns SHORT_NSN_MATCH if either or both has no region specified, + * or the region specified is the same, and one NSN could be a shorter version + * of the other number. This includes the case where one has an extension + * specified, and the other does not. Returns NO_MATCH otherwise. For example, + * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers + * +1 345 657 1234 and 345 657 are a NO_MATCH. + * + * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to + * compare. If it is a string it can contain formatting, and can have + * country calling code specified with + at the start. + * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to + * compare. If it is a string it can contain formatting, and can have + * country calling code specified with + at the start. + * @return {MatchType} NOT_A_NUMBER, NO_MATCH, + * SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of + * equality of the two numbers, described in the method definition. + */ +- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn error:(NSError**)error +{ + NBEMatchType res = 0; + @try { + res = [self isNumberMatch:firstNumberIn second:secondNumberIn]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + +- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn +{ + // If the input arguements are strings parse them to a proto buffer format. + // Else make copies of the phone numbers so that the numbers passed in are not + // edited. + /** @type {i18n.phonenumbers.PhoneNumber} */ + NBPhoneNumber *firstNumber = nil, *secondNumber = nil; + + if ([firstNumberIn isKindOfClass:[NSString class]]) { + // First see if the first number has an implicit country calling code, by + // attempting to parse it. + NSError *anError; + firstNumber = [self parse:firstNumberIn defaultRegion:NB_UNKNOWN_REGION error:&anError]; + + if (anError != nil) { + if ([anError.domain isEqualToString:@"INVALID_COUNTRY_CODE"] == NO) { + return NBEMatchTypeNOT_A_NUMBER; + } + // The first number has no country calling code. EXACT_MATCH is no longer + // possible. We parse it as if the region was the same as that for the + // second number, and if EXACT_MATCH is returned, we replace this with + // NSN_MATCH. + if ([secondNumberIn isKindOfClass:[NSString class]] == NO) { + NSString *secondNumberRegion = [self getRegionCodeForCountryCode:((NBPhoneNumber*)secondNumberIn).countryCode]; + if (secondNumberRegion != NB_UNKNOWN_REGION) { + NSError *aNestedError; + firstNumber = [self parse:firstNumberIn defaultRegion:secondNumberRegion error:&aNestedError]; + + if (aNestedError != nil) { + return NBEMatchTypeNOT_A_NUMBER; + } + + NBEMatchType match = [self isNumberMatch:firstNumber second:secondNumberIn]; + if (match == NBEMatchTypeEXACT_MATCH) { + return NBEMatchTypeNSN_MATCH; + } + return match; + } + } + // If the second number is a string or doesn't have a valid country + // calling code, we parse the first number without country calling code. + NSError *aNestedError; + firstNumber = [self parseHelper:firstNumberIn defaultRegion:nil keepRawInput:NO checkRegion:NO error:&aNestedError]; + if (aNestedError != nil) { + return NBEMatchTypeNOT_A_NUMBER; + } + } + } else { + firstNumber = [firstNumberIn copy]; + } + + if ([secondNumberIn isKindOfClass:[NSString class]]) { + NSError *parseError; + secondNumber = [self parse:secondNumberIn defaultRegion:NB_UNKNOWN_REGION error:&parseError]; + if (parseError != nil) { + if ([parseError.domain isEqualToString:@"INVALID_COUNTRY_CODE"] == NO) { + return NBEMatchTypeNOT_A_NUMBER; + } + return [self isNumberMatch:secondNumberIn second:firstNumber]; + } else { + return [self isNumberMatch:firstNumberIn second:secondNumber]; + } + } + else { + secondNumber = [secondNumberIn copy]; + } + + // First clear raw_input, country_code_source and + // preferred_domestic_carrier_code fields and any empty-string extensions so + // that we can use the proto-buffer equality method. + firstNumber.rawInput = @""; + [firstNumber clearCountryCodeSource]; + firstNumber.preferredDomesticCarrierCode = @""; + + secondNumber.rawInput = @""; + [secondNumber clearCountryCodeSource]; + secondNumber.preferredDomesticCarrierCode = @""; + + if (firstNumber.extension != nil && firstNumber.extension.length == 0) { + firstNumber.extension = nil; + } + + if (secondNumber.extension != nil && secondNumber.extension.length == 0) { + secondNumber.extension = nil; + } + + // Early exit if both had extensions and these are different. + if ([NBMetadataHelper hasValue:firstNumber.extension] && [NBMetadataHelper hasValue:secondNumber.extension] && + [firstNumber.extension isEqualToString:secondNumber.extension] == NO) { + return NBEMatchTypeNO_MATCH; + } + + NSNumber *firstNumberCountryCode = firstNumber.countryCode; + NSNumber *secondNumberCountryCode = secondNumber.countryCode; + + // Both had country_code specified. + if (![firstNumberCountryCode isEqualToNumber:@0] && ![secondNumberCountryCode isEqualToNumber:@0]) { + if ([firstNumber isEqual:secondNumber]) { + return NBEMatchTypeEXACT_MATCH; + } else if ([firstNumberCountryCode isEqualToNumber:secondNumberCountryCode] && [self isNationalNumberSuffixOfTheOther:firstNumber second:secondNumber]) { + // A SHORT_NSN_MATCH occurs if there is a difference because of the + // presence or absence of an 'Italian leading zero', the presence or + // absence of an extension, or one NSN being a shorter variant of the + // other. + return NBEMatchTypeSHORT_NSN_MATCH; + } + // This is not a match. + return NBEMatchTypeNO_MATCH; + } + // Checks cases where one or both country_code fields were not specified. To + // make equality checks easier, we first set the country_code fields to be + // equal. + firstNumber.countryCode = @0; + secondNumber.countryCode = @0; + // If all else was the same, then this is an NSN_MATCH. + if ([firstNumber isEqual:secondNumber]) { + return NBEMatchTypeNSN_MATCH; + } + + if ([self isNationalNumberSuffixOfTheOther:firstNumber second:secondNumber]) { + return NBEMatchTypeSHORT_NSN_MATCH; + } + return NBEMatchTypeNO_MATCH; +} + + +/** + * Returns NO when one national number is the suffix of the other or both are + * the same. + * + * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber + * object. + * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber + * object. + * @return {boolean} NO if one PhoneNumber is the suffix of the other one. + * @private + */ +- (BOOL)isNationalNumberSuffixOfTheOther:(NBPhoneNumber*)firstNumber second:(NBPhoneNumber*)secondNumber +{ + NSString *firstNumberNationalNumber = [NSString stringWithFormat:@"%@", firstNumber.nationalNumber]; + NSString *secondNumberNationalNumber = [NSString stringWithFormat:@"%@", secondNumber.nationalNumber]; + + // Note that endsWith returns NO if the numbers are equal. + return [firstNumberNationalNumber hasSuffix:secondNumberNationalNumber] || + [secondNumberNationalNumber hasSuffix:firstNumberNationalNumber]; +} + + +/** + * Returns NO if the number can be dialled from outside the region, or + * unknown. If the number can only be dialled from within the region, returns + * NO. Does not check the number is a valid number. + * TODO: Make this method public when we have enough metadata to make it + * worthwhile. Currently visible for testing purposes only. + * + * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we + * want to know whether it is diallable from outside the region. + * @return {boolean} NO if the number can only be dialled from within the + * country. + */ +- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number error:(NSError**)error +{ + BOOL res = NO; + @try { + res = [self canBeInternationallyDialled:number]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason + forKey:NSLocalizedDescriptionKey]; + if (error != NULL) + (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo]; + } + return res; +} + +- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number +{ + NBMetadataHelper *helper = [[NBMetadataHelper alloc] init]; + NBPhoneMetaData *metadata = [helper getMetadataForRegion:[self getRegionCodeForNumber:number]]; + if (metadata == nil) { + // Note numbers belonging to non-geographical entities (e.g. +800 numbers) + // are always internationally diallable, and will be caught here. + return YES; + } + NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number]; + return [self isNumberMatchingDesc:nationalSignificantNumber numberDesc:metadata.noInternationalDialling] == NO; +} + + +/** + * Check whether the entire input sequence can be matched against the regular + * expression. + * + * @param {!RegExp|string} regex the regular expression to match against. + * @param {string} str the string to test. + * @return {boolean} NO if str can be matched entirely against regex. + * @private + */ +- (BOOL)matchesEntirely:(NSString *)regex string:(NSString *)str +{ + if ([regex isEqualToString:@"NA"]) { + return NO; + } + + NSError *error = nil; + NSRegularExpression *currentPattern = [self entireRegularExpressionWithPattern:regex options:0 error:&error]; + NSRange stringRange = NSMakeRange(0, str.length); + NSTextCheckingResult *matchResult = [currentPattern firstMatchInString:str options:NSMatchingAnchored range:stringRange]; + + if (matchResult != nil) { + BOOL matchIsEntireString = NSEqualRanges(matchResult.range, stringRange); + if (matchIsEntireString) + { + return YES; + } + } + + return NO; +} + +@end