├── .gitignore ├── TelegramCore.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── TelegramCore.xcscheme ├── TelegramCore ├── AccessSecureId.swift ├── Account.swift ├── AccountEnvironmentAttribute.swift ├── AccountIntermediateState.swift ├── AccountManager.swift ├── AccountSortOrderAttribute.swift ├── AccountState.swift ├── AccountStateManagementUtils.swift ├── AccountStateManager.swift ├── AccountStateReset.swift ├── AccountViewTracker.swift ├── ActiveSessionsContext.swift ├── AddPeerMember.swift ├── AddressNames.swift ├── Api0.swift ├── Api1.swift ├── Api2.swift ├── Api3.swift ├── ApiGroupOrChannel.swift ├── ApiUtils.swift ├── AppChangelog.swift ├── AppChangelogState.swift ├── AppConfiguration.swift ├── ApplyMaxReadIndexInteractively.swift ├── ApplyUpdateMessage.swift ├── ArchivedStickerPacks.swift ├── ArchivedStickerPacksInfo.swift ├── AuthorSignatureMessageAttribute.swift ├── Authorization.swift ├── AutodownloadSettings.swift ├── AutoremoveTimeoutMessageAttribute.swift ├── BlockedPeers.swift ├── BlockedPeersContext.swift ├── BotInfo.swift ├── BotPaymentForm.swift ├── Buffer.swift ├── CacheStorageSettings.swift ├── CachedChannelData.swift ├── CachedChannelParticipants.swift ├── CachedGroupData.swift ├── CachedGroupParticipants.swift ├── CachedSentMediaReferences.swift ├── CachedStickerPack.swift ├── CachedUserData.swift ├── CallSessionManager.swift ├── CanSendMessagesToPeer.swift ├── CancelAccountReset.swift ├── ChangeAccountPhoneNumber.swift ├── ChangePeerNotificationSettings.swift ├── ChannelAdminEventLogContext.swift ├── ChannelAdminEventLogs.swift ├── ChannelAdmins.swift ├── ChannelBlacklist.swift ├── ChannelCreation.swift ├── ChannelHistoryAvailabilitySettings.swift ├── ChannelMembers.swift ├── ChannelMessageStateVersionAttribute.swift ├── ChannelParticipants.swift ├── ChannelState.swift ├── ChannelStats.swift ├── ChatContextResult.swift ├── ChatHistoryPreloadManager.swift ├── ChatOnlineMembers.swift ├── CheckPeerChatServiceActions.swift ├── ClearCloudDrafts.swift ├── CloudChatRemoveMessagesOperation.swift ├── CloudFileMediaResource.swift ├── CloudMediaResourceParameters.swift ├── CollectCacheUsageStats.swift ├── Config │ └── TelegramCore.xcconfig ├── ConfirmTwoStepRecoveryEmail.swift ├── ConsumableContentMessageAttribute.swift ├── ConsumablePersonalMentionMessageAttribute.swift ├── ConsumePersonalMessageAction.swift ├── ContactManagement.swift ├── ContactSyncManager.swift ├── ContactsSettings.swift ├── ContentPrivacySettings.swift ├── ContentRequiresValidationMessageAttribute.swift ├── ConvertGroupToSupergroup.swift ├── CoreSettings.swift ├── CreateGroup.swift ├── CreateSecretChat.swift ├── Crypto.h ├── Crypto.m ├── DecryptedResourceData.swift ├── DeepLinkInfo.swift ├── DeleteMessages.swift ├── DeleteMessagesInteractively.swift ├── DeserializeFunctionResponse.swift ├── DeviceContact.swift ├── Download.swift ├── EarliestUnseenPersonalMentionMessage.swift ├── EditedMessageAttribute.swift ├── Either.swift ├── EmojiKeywords.swift ├── EncryptedMediaResource.swift ├── EnqueueMessage.swift ├── ExportMessageLink.swift ├── ExportedInvitation.swift ├── FeaturedStickerPack.swift ├── Fetch.swift ├── FetchChatList.swift ├── FetchHttpResource.swift ├── FetchSecretFileResource.swift ├── FetchedMediaResource.swift ├── FindChannelById.swift ├── ForwardGame.swift ├── ForwardSourceInfoAttribute.swift ├── GlobalNotificationSettings.swift ├── GlobalTelegramCoreConfiguration.swift ├── GrantSecureIdAccess.swift ├── GroupFeedPeers.swift ├── GroupReturnAndLeft.swift ├── GroupsInCommon.swift ├── HistoryViewChannelStateValidation.swift ├── Holes.swift ├── ImageRepresentationsUtils.swift ├── ImportContact.swift ├── Info.plist ├── InitializeAccountAfterLogin.swift ├── InlineBotMessageAttribute.swift ├── InstallInteractiveReadMessagesAction.swift ├── InstantPage.swift ├── InteractivePhoneFormatter.swift ├── InvitationLinks.swift ├── JSON.swift ├── JoinChannel.swift ├── JoinLink.swift ├── LimitsConfiguration.swift ├── LoadMessagesIfNecessary.swift ├── LoadedPeer.swift ├── LoadedPeerFromMessage.swift ├── LoadedStickerPack.swift ├── Localization.swift ├── LocalizationInfo.swift ├── LocalizationListState.swift ├── LocalizationPreview.swift ├── LocalizationSettings.swift ├── Localizations.swift ├── Log.swift ├── LoggedOutAccountAttribute.swift ├── LoggingSettings.swift ├── MD5.swift ├── ManageChannelDiscussionGroup.swift ├── ManagedAccountPresence.swift ├── ManagedAppConfigurationUpdates.swift ├── ManagedAutodownloadSettingsUpdates.swift ├── ManagedAutoremoveMessageOperations.swift ├── ManagedChatListHoles.swift ├── ManagedCloudChatRemoveMessagesOperations.swift ├── ManagedConfigurationUpdates.swift ├── ManagedConsumePersonalMessagesActions.swift ├── ManagedGlobalNotificationSettings.swift ├── ManagedLocalInputActivities.swift ├── ManagedLocalizationUpdatesOperations.swift ├── ManagedMessageHistoryHoles.swift ├── ManagedNotificationSettingsBehaviors.swift ├── ManagedPendingPeerNotificationSettings.swift ├── ManagedProxyInfoUpdates.swift ├── ManagedRecentStickers.swift ├── ManagedSecretChatOutgoingOperations.swift ├── ManagedServiceViews.swift ├── ManagedSynchronizeAppLogEventsOperations.swift ├── ManagedSynchronizeChatInputStateOperations.swift ├── ManagedSynchronizeConsumeMessageContentsOperations.swift ├── ManagedSynchronizeEmojiKeywordsOperations.swift ├── ManagedSynchronizeGroupMessageStats.swift ├── ManagedSynchronizeGroupedPeersOperations.swift ├── ManagedSynchronizeInstalledStickerPacksOperations.swift ├── ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift ├── ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift ├── ManagedSynchronizePeerReadStates.swift ├── ManagedSynchronizePinnedChatsOperations.swift ├── ManagedSynchronizeRecentlyUsedMediaOperations.swift ├── ManagedSynchronizeSavedGifsOperations.swift ├── ManagedSynchronizeSavedStickersOperations.swift ├── ManagedVoipConfigurationUpdates.swift ├── MarkAllChatsAsRead.swift ├── MarkMessageContentAsConsumedInteractively.swift ├── MediaResourceApiUtils.swift ├── MediaResourceNetworkStatsTag.swift ├── MemoryBufferExtensions.swift ├── MessageMediaPreuploadManager.swift ├── MessageUtils.swift ├── MonotonicTime.h ├── MonotonicTime.m ├── MonotonicTime.swift ├── MultipartFetch.swift ├── MultipartUpload.swift ├── MultipeerManager.swift ├── MultiplexedRequestManager.swift ├── Namespaces.swift ├── Network.swift ├── NetworkLogging.h ├── NetworkLogging.m ├── NetworkSettings.swift ├── NetworkType.swift ├── NotificationAutolockReportManager.swift ├── NotificationExceptionsList.swift ├── NotificationInfoMessageAttribute.swift ├── OutgoingChatContextResultMessageAttribute.swift ├── OutgoingContentInfoMessageAttribute.swift ├── OutgoingMessageInfoAttribute.swift ├── OutgoingMessageWithChatContextResult.swift ├── PeerAccessRestrictionInfo.swift ├── PeerAdmins.swift ├── PeerCommands.swift ├── PeerGroupMessageStateVersionAttribute.swift ├── PeerInputActivity.swift ├── PeerInputActivityManager.swift ├── PeerLiveLocationsContext.swift ├── PeerParticipants.swift ├── PeerPhotoUpdater.swift ├── PeerReportStatus.swift ├── PeerSpecificStickerPack.swift ├── PeerUtils.swift ├── PendingMessageManager.swift ├── PendingMessageUploadedContent.swift ├── PhoneNumber.swift ├── PhoneNumbers.swift ├── Polls.swift ├── PrivacySettings.swift ├── ProcessSecretChatIncomingDecryptedOperations.swift ├── ProcessSecretChatIncomingEncryptedOperations.swift ├── ProxyServersStatuses.swift ├── ProxySettings.swift ├── Random.swift ├── RateCall.swift ├── Reachability.h ├── Reachability.m ├── RecentAccountSession.swift ├── RecentAccountSessions.swift ├── RecentMediaItem.swift ├── RecentPeerItem.swift ├── RecentPeers.swift ├── RecentWebSessions.swift ├── RecentlySearchedPeerIds.swift ├── RecentlyUsedHashtags.swift ├── Regex.swift ├── RegisterNotificationToken.swift ├── RegularChatState.swift ├── RemoteStorageConfiguration.swift ├── RemovePeerChat.swift ├── RemovePeerMember.swift ├── ReplyMarkupMessageAttribute.swift ├── ReplyMessageAttribute.swift ├── ReportPeer.swift ├── RequestChatContextResults.swift ├── RequestEditMessage.swift ├── RequestMessageActionCallback.swift ├── RequestPhoneNumber.swift ├── RequestSecureIdForm.swift ├── RequestStartBot.swift ├── RequestUserPhotos.swift ├── ResolvePeerByName.swift ├── RichText.swift ├── SaveSecureIdValue.swift ├── SavedStickerItem.swift ├── SearchBotsConfiguration.swift ├── SearchGroupMembers.swift ├── SearchMessages.swift ├── SearchPeers.swift ├── SearchStickers.swift ├── SecretApiLayer46.swift ├── SecretApiLayer73.swift ├── SecretApiLayer8.swift ├── SecretChatEncryption.swift ├── SecretChatEncryptionConfig.swift ├── SecretChatFileReference.swift ├── SecretChatIncomingDecryptedOperation.swift ├── SecretChatIncomingEncryptedOperation.swift ├── SecretChatKeychain.swift ├── SecretChatLayerNegotiation.swift ├── SecretChatOutgoingOperation.swift ├── SecretChatRekeySession.swift ├── SecretChatState.swift ├── SecureFileMediaResource.swift ├── SecureIdAddressValue.swift ├── SecureIdBankStatementValue.swift ├── SecureIdConfiguration.swift ├── SecureIdDataTypes.swift ├── SecureIdDriversLicenseValue.swift ├── SecureIdEmailValue.swift ├── SecureIdForm.swift ├── SecureIdIDCardValue.swift ├── SecureIdInternalPassportValue.swift ├── SecureIdPadding.swift ├── SecureIdPassportRegistrationValue.swift ├── SecureIdPassportValue.swift ├── SecureIdPersonalDetailsValue.swift ├── SecureIdPhoneValue.swift ├── SecureIdRentalAgreementValue.swift ├── SecureIdTemporaryRegistrationValue.swift ├── SecureIdUtilityBillValue.swift ├── SecureIdValue.swift ├── SecureIdValueAccessContext.swift ├── SecureIdValueContentError.swift ├── SecureIdVerificationDocumentReference.swift ├── Serialization.swift ├── SetSecretChatMessageAutoremoveTimeoutInteractively.swift ├── SingleMessageView.swift ├── SourceReferenceMessageAttribute.swift ├── SplitTest.swift ├── StandaloneSendMessage.swift ├── StandaloneUploadedMedia.swift ├── StickerManagement.swift ├── StickerPack.swift ├── StickerPackInteractiveOperations.swift ├── StickerSetInstallation.swift ├── StoreMessage_Telegram.swift ├── StringFormat.swift ├── SuggestedLocalizationEntry.swift ├── SupportPeerId.swift ├── SynchronizeAppLogEventsOperation.swift ├── SynchronizeChatInputStateOperation.swift ├── SynchronizeConsumeMessageContentsOperation.swift ├── SynchronizeEmojiKeywordsOperation.swift ├── SynchronizeGroupedPeersOperation.swift ├── SynchronizeInstalledStickerPacksOperations.swift ├── SynchronizeLocalizationUpdatesOperation.swift ├── SynchronizeMarkAllUnseenPersonalMessagesOperation.swift ├── SynchronizePeerReadState.swift ├── SynchronizePinnedChatsOperation.swift ├── SynchronizeRecentlyUsedMediaOperations.swift ├── SynchronizeSavedGifsOperation.swift ├── SynchronizeSavedStickersOperation.swift ├── SynchronizeableChatInputState.swift ├── TelegramChannel.swift ├── TelegramChannelAdminRights.swift ├── TelegramChannelBannedRights.swift ├── TelegramCore.h ├── TelegramCoreIncludes.h ├── TelegramCorePrivate │ └── module.modulemap ├── TelegramDeviceContactImportInfo.swift ├── TelegramGroup.swift ├── TelegramMediaAction.swift ├── TelegramMediaContact.swift ├── TelegramMediaExpiredContent.swift ├── TelegramMediaFile.swift ├── TelegramMediaGame.swift ├── TelegramMediaImage.swift ├── TelegramMediaInvoice.swift ├── TelegramMediaMap.swift ├── TelegramMediaPoll.swift ├── TelegramMediaResource.swift ├── TelegramMediaWebDocument.swift ├── TelegramMediaWebpage.swift ├── TelegramPeerNotificationSettings.swift ├── TelegramSecretChat.swift ├── TelegramUser.swift ├── TelegramUserPresence.swift ├── TeleramMediaUnsupported.swift ├── TermsOfService.swift ├── TextEntitiesMessageAttribute.swift ├── ToggleChannelSignatures.swift ├── TogglePeerChatPinned.swift ├── TwoStepVerification.swift ├── Unixtime.swift ├── UpdateAccountPeerName.swift ├── UpdateCachedPeerData.swift ├── UpdateContactName.swift ├── UpdateGroup.swift ├── UpdateGroupSpecificStickerset.swift ├── UpdateMessageMedia.swift ├── UpdateMessageService.swift ├── UpdatePeerChatInterfaceState.swift ├── UpdatePeerInfo.swift ├── UpdatePeers.swift ├── UpdatePinnedMessage.swift ├── UpdateSecretChat.swift ├── UpdatedAccountPrivacySettings.swift ├── UpdatesApiUtils.swift ├── UploadSecureIdFile.swift ├── VerifySecureIdValue.swift ├── ViewCountMessageAttribute.swift ├── VoipConfiguration.swift ├── Wallpaper.swift ├── Wallpapers.swift ├── WebpagePreview.swift ├── module.private-mac.modulemap └── module.private.modulemap ├── TelegramCoreMac ├── Info.plist └── TelegramCoreMac.h ├── TelegramCoreTests ├── Info.plist └── TelegramCoreTests.m └── third-party └── libphonenumber-iOS ├── NBAsYouTypeFormatter.h ├── NBAsYouTypeFormatter.m ├── NBMetadataCore.h ├── NBMetadataCore.m ├── NBMetadataCoreMapper.h ├── NBMetadataCoreMapper.m ├── NBMetadataCoreTest.h ├── NBMetadataCoreTest.m ├── NBMetadataCoreTestMapper.h ├── NBMetadataCoreTestMapper.m ├── NBMetadataHelper.h ├── NBMetadataHelper.m ├── NBNumberFormat.h ├── NBNumberFormat.m ├── NBPhoneMetaData.h ├── NBPhoneMetaData.m ├── NBPhoneMetaDataGenerator.h ├── NBPhoneMetaDataGenerator.m ├── NBPhoneNumber.h ├── NBPhoneNumber.m ├── NBPhoneNumberDefines.h ├── NBPhoneNumberDefines.m ├── NBPhoneNumberDesc.h ├── NBPhoneNumberDesc.m ├── NBPhoneNumberUtil.h └── NBPhoneNumberUtil.m /.gitignore: -------------------------------------------------------------------------------- 1 | fastlane/README.md 2 | fastlane/report.xml 3 | fastlane/test_output/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.xcscmblueprint 15 | *.moved-aside 16 | DerivedData 17 | *.hmap 18 | *.ipa 19 | *.xcuserstate 20 | .DS_Store 21 | *.dSYM 22 | *.dSYM.zip 23 | *.ipa 24 | */xcuserdata/* 25 | -------------------------------------------------------------------------------- /TelegramCore.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TelegramCore/AccountEnvironmentAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public enum AccountEnvironment: Int32 { 9 | case production = 0 10 | case test = 1 11 | } 12 | 13 | public final class AccountEnvironmentAttribute: AccountRecordAttribute { 14 | public let environment: AccountEnvironment 15 | 16 | public init(environment: AccountEnvironment) { 17 | self.environment = environment 18 | } 19 | 20 | public init(decoder: PostboxDecoder) { 21 | self.environment = AccountEnvironment(rawValue: decoder.decodeInt32ForKey("environment", orElse: 0)) ?? .production 22 | } 23 | 24 | public func encode(_ encoder: PostboxEncoder) { 25 | encoder.encodeInt32(self.environment.rawValue, forKey: "environment") 26 | } 27 | 28 | public func isEqual(to: AccountRecordAttribute) -> Bool { 29 | guard let to = to as? AccountEnvironmentAttribute else { 30 | return false 31 | } 32 | if self.environment != to.environment { 33 | return false 34 | } 35 | return true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TelegramCore/AccountSortOrderAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class AccountSortOrderAttribute: AccountRecordAttribute { 9 | public let order: Int32 10 | 11 | public init(order: Int32) { 12 | self.order = order 13 | } 14 | 15 | public init(decoder: PostboxDecoder) { 16 | self.order = decoder.decodeInt32ForKey("order", orElse: 0) 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt32(self.order, forKey: "order") 21 | } 22 | 23 | public func isEqual(to: AccountRecordAttribute) -> Bool { 24 | guard let to = to as? AccountSortOrderAttribute else { 25 | return false 26 | } 27 | if self.order != to.order { 28 | return false 29 | } 30 | return true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TelegramCore/AppChangelog.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | func managedAppChangelog(postbox: Postbox, network: Network, stateManager: AccountStateManager, appVersion: String) -> Signal { 13 | return stateManager.pollStateUpdateCompletion() 14 | |> take(1) 15 | |> mapToSignal { _ -> Signal in 16 | return postbox.transaction { transaction -> AppChangelogState in 17 | return transaction.getPreferencesEntry(key: PreferencesKeys.appChangelogState) as? AppChangelogState ?? AppChangelogState.default 18 | } 19 | |> mapToSignal { appChangelogState -> Signal in 20 | let appChangelogState = appChangelogState 21 | if appChangelogState.checkedVersion == appVersion { 22 | return .complete() 23 | } 24 | let previousVersion = appChangelogState.previousVersion 25 | return network.request(Api.functions.help.getAppChangelog(prevAppVersion: previousVersion)) 26 | |> map(Optional.init) 27 | |> `catch` { _ -> Signal in 28 | return .single(nil) 29 | } 30 | |> mapToSignal { updates -> Signal in 31 | if let updates = updates { 32 | stateManager.addUpdates(updates) 33 | } 34 | 35 | return postbox.transaction { transaction in 36 | updateAppChangelogState(transaction: transaction, { state in 37 | var state = state 38 | state.checkedVersion = appVersion 39 | state.previousVersion = appVersion 40 | return state 41 | }) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /TelegramCore/AppChangelogState.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | struct AppChangelogState: PreferencesEntry, Equatable { 13 | var checkedVersion: String 14 | var previousVersion: String 15 | 16 | static var `default` = AppChangelogState(checkedVersion: "", previousVersion: "5.0.8") 17 | 18 | init(checkedVersion: String, previousVersion: String) { 19 | self.checkedVersion = checkedVersion 20 | self.previousVersion = previousVersion 21 | } 22 | 23 | init(decoder: PostboxDecoder) { 24 | self.checkedVersion = decoder.decodeStringForKey("checkedVersion", orElse: "") 25 | self.previousVersion = decoder.decodeStringForKey("previousVersion", orElse: "") 26 | } 27 | 28 | func encode(_ encoder: PostboxEncoder) { 29 | encoder.encodeString(self.checkedVersion, forKey: "checkedVersion") 30 | encoder.encodeString(self.previousVersion, forKey: "previousVersion") 31 | } 32 | 33 | func isEqual(to: PreferencesEntry) -> Bool { 34 | guard let to = to as? AppChangelogState else { 35 | return false 36 | } 37 | 38 | return self == to 39 | } 40 | } 41 | 42 | func updateAppChangelogState(transaction: Transaction, _ f: @escaping (AppChangelogState) -> AppChangelogState) { 43 | transaction.updatePreferencesEntry(key: PreferencesKeys.appChangelogState, { current in 44 | return f((current as? AppChangelogState) ?? AppChangelogState.default) 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /TelegramCore/AppConfiguration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct AppConfiguration: PreferencesEntry, Equatable { 9 | public var data: JSON? 10 | 11 | public static var defaultValue: AppConfiguration { 12 | return AppConfiguration(data: nil) 13 | } 14 | 15 | init(data: JSON?) { 16 | self.data = data 17 | } 18 | 19 | public init(decoder: PostboxDecoder) { 20 | self.data = decoder.decodeObjectForKey("data", decoder: { JSON(decoder: $0) }) as? JSON 21 | } 22 | 23 | public func encode(_ encoder: PostboxEncoder) { 24 | if let data = self.data { 25 | encoder.encodeObject(data, forKey: "data") 26 | } else { 27 | encoder.encodeNil(forKey: "data") 28 | } 29 | } 30 | 31 | public func isEqual(to: PreferencesEntry) -> Bool { 32 | guard let to = to as? AppConfiguration else { 33 | return false 34 | } 35 | return self == to 36 | } 37 | } 38 | 39 | public func currentAppConfiguration(transaction: Transaction) -> AppConfiguration { 40 | if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration { 41 | return entry 42 | } else { 43 | return AppConfiguration.defaultValue 44 | } 45 | } 46 | 47 | func updateAppConfiguration(transaction: Transaction, _ f: (AppConfiguration) -> AppConfiguration) { 48 | let current = currentAppConfiguration(transaction: transaction) 49 | let updated = f(current) 50 | if updated != current { 51 | transaction.setPreferencesEntry(key: PreferencesKeys.appConfiguration, value: updated) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /TelegramCore/ArchivedStickerPacks.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public enum ArchivedStickerPacksNamespace: Int32 { 11 | case stickers = 0 12 | case masks = 1 13 | } 14 | 15 | public final class ArchivedStickerPackItem { 16 | public let info: StickerPackCollectionInfo 17 | public let topItems: [StickerPackItem] 18 | 19 | public init(info: StickerPackCollectionInfo, topItems: [StickerPackItem]) { 20 | self.info = info 21 | self.topItems = topItems 22 | } 23 | } 24 | 25 | public func archivedStickerPacks(account: Account, namespace: ArchivedStickerPacksNamespace = .stickers) -> Signal<[ArchivedStickerPackItem], NoError> { 26 | var flags: Int32 = 0 27 | if case .masks = namespace { 28 | flags |= 1 << 0 29 | } 30 | return account.network.request(Api.functions.messages.getArchivedStickers(flags: flags, offsetId: 0, limit: 100)) 31 | |> map { result -> [ArchivedStickerPackItem] in 32 | var archivedItems: [ArchivedStickerPackItem] = [] 33 | switch result { 34 | case let .archivedStickers(_, sets): 35 | for set in sets { 36 | let (info, items) = parsePreviewStickerSet(set) 37 | archivedItems.append(ArchivedStickerPackItem(info: info, topItems: items)) 38 | } 39 | } 40 | return archivedItems 41 | } |> `catch` { _ in 42 | return .single([]) 43 | } 44 | } 45 | 46 | public func removeArchivedStickerPack(account: Account, info: StickerPackCollectionInfo) -> Signal { 47 | return account.network.request(Api.functions.messages.uninstallStickerSet(stickerset: Api.InputStickerSet.inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) 48 | |> `catch` { _ -> Signal in 49 | return .single(.boolFalse) 50 | } 51 | |> mapToSignal { _ -> Signal in 52 | return .complete() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /TelegramCore/ArchivedStickerPacksInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct ArchivedStickerPacksInfoId { 9 | public let rawValue: MemoryBuffer 10 | public let id: Int32 11 | 12 | init(_ rawValue: MemoryBuffer) { 13 | self.rawValue = rawValue 14 | assert(rawValue.length == 4) 15 | var idValue: Int32 = 0 16 | memcpy(&idValue, rawValue.memory, 4) 17 | self.id = idValue 18 | } 19 | 20 | init(_ id: Int32) { 21 | self.id = id 22 | var idValue: Int32 = id 23 | self.rawValue = MemoryBuffer(memory: malloc(4)!, capacity: 4, length: 4, freeWhenDone: true) 24 | memcpy(self.rawValue.memory, &idValue, 4) 25 | } 26 | } 27 | 28 | public final class ArchivedStickerPacksInfo: OrderedItemListEntryContents { 29 | public let count: Int32 30 | 31 | init(count: Int32) { 32 | self.count = count 33 | } 34 | 35 | public init(decoder: PostboxDecoder) { 36 | self.count = decoder.decodeInt32ForKey("c", orElse: 0) 37 | } 38 | 39 | public func encode(_ encoder: PostboxEncoder) { 40 | encoder.encodeInt32(self.count, forKey: "c") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TelegramCore/AuthorSignatureMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class AuthorSignatureMessageAttribute: MessageAttribute { 9 | public let signature: String 10 | 11 | public let associatedPeerIds: [PeerId] = [] 12 | 13 | init(signature: String) { 14 | self.signature = signature 15 | } 16 | 17 | required public init(decoder: PostboxDecoder) { 18 | self.signature = decoder.decodeStringForKey("s", orElse: "") 19 | } 20 | 21 | public func encode(_ encoder: PostboxEncoder) { 22 | encoder.encodeString(self.signature, forKey: "s") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TelegramCore/AutoremoveTimeoutMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public class AutoremoveTimeoutMessageAttribute: MessageAttribute { 13 | public let timeout: Int32 14 | public let countdownBeginTime: Int32? 15 | 16 | public var associatedMessageIds: [MessageId] = [] 17 | 18 | public init(timeout: Int32, countdownBeginTime: Int32?) { 19 | self.timeout = timeout 20 | self.countdownBeginTime = countdownBeginTime 21 | } 22 | 23 | required public init(decoder: PostboxDecoder) { 24 | self.timeout = decoder.decodeInt32ForKey("t", orElse: 0) 25 | self.countdownBeginTime = decoder.decodeOptionalInt32ForKey("c") 26 | } 27 | 28 | public func encode(_ encoder: PostboxEncoder) { 29 | encoder.encodeInt32(self.timeout, forKey: "t") 30 | if let countdownBeginTime = self.countdownBeginTime { 31 | encoder.encodeInt32(countdownBeginTime, forKey: "c") 32 | } else { 33 | encoder.encodeNil(forKey: "c") 34 | } 35 | } 36 | } 37 | 38 | public extension Message { 39 | public var containsSecretMedia: Bool { 40 | var found = false 41 | for attribute in self.attributes { 42 | if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { 43 | if attribute.timeout > 1 * 60 { 44 | return false 45 | } 46 | found = true 47 | break 48 | } 49 | } 50 | 51 | if !found { 52 | return false 53 | } 54 | 55 | for media in self.media { 56 | switch media { 57 | case _ as TelegramMediaImage: 58 | return true 59 | case let file as TelegramMediaFile: 60 | if file.isVideo || file.isAnimated || file.isVoice { 61 | return true 62 | } 63 | default: 64 | break 65 | } 66 | } 67 | 68 | return false 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TelegramCore/BotInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct BotCommand: PostboxCoding, Equatable { 9 | public let text: String 10 | public let description: String 11 | 12 | init(text: String, description: String) { 13 | self.text = text 14 | self.description = description 15 | } 16 | 17 | public init(decoder: PostboxDecoder) { 18 | self.text = decoder.decodeStringForKey("t", orElse: "") 19 | self.description = decoder.decodeStringForKey("d", orElse: "") 20 | } 21 | 22 | public func encode(_ encoder: PostboxEncoder) { 23 | encoder.encodeString(self.text, forKey: "t") 24 | encoder.encodeString(self.description, forKey: "d") 25 | } 26 | 27 | public static func ==(lhs: BotCommand, rhs: BotCommand) -> Bool { 28 | return lhs.text == rhs.text && lhs.description == rhs.description 29 | } 30 | } 31 | 32 | public final class BotInfo: PostboxCoding, Equatable { 33 | public let description: String 34 | public let commands: [BotCommand] 35 | 36 | init(description: String, commands: [BotCommand]) { 37 | self.description = description 38 | self.commands = commands 39 | } 40 | 41 | public init(decoder: PostboxDecoder) { 42 | self.description = decoder.decodeStringForKey("d", orElse: "") 43 | self.commands = decoder.decodeObjectArrayWithDecoderForKey("c") 44 | } 45 | 46 | public func encode(_ encoder: PostboxEncoder) { 47 | encoder.encodeString(self.description, forKey: "d") 48 | encoder.encodeObjectArray(self.commands, forKey: "c") 49 | } 50 | 51 | public static func ==(lhs: BotInfo, rhs: BotInfo) -> Bool { 52 | return lhs.description == rhs.description && lhs.commands == rhs.commands 53 | } 54 | } 55 | 56 | extension BotInfo { 57 | convenience init(apiBotInfo: Api.BotInfo) { 58 | switch apiBotInfo { 59 | case let .botInfo(_, description, commands): 60 | self.init(description: description, commands: commands.map { command in 61 | switch command { 62 | case let .botCommand(command, description): 63 | return BotCommand(text: command, description: description) 64 | } 65 | }) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /TelegramCore/CacheStorageSettings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public struct CacheStorageSettings: PreferencesEntry, Equatable { 11 | public let defaultCacheStorageTimeout: Int32 12 | 13 | public static var defaultSettings: CacheStorageSettings { 14 | return CacheStorageSettings(defaultCacheStorageTimeout: Int32.max) 15 | } 16 | 17 | init(defaultCacheStorageTimeout: Int32) { 18 | self.defaultCacheStorageTimeout = defaultCacheStorageTimeout 19 | } 20 | 21 | public init(decoder: PostboxDecoder) { 22 | self.defaultCacheStorageTimeout = decoder.decodeInt32ForKey("dt", orElse: 0) 23 | } 24 | 25 | public func encode(_ encoder: PostboxEncoder) { 26 | encoder.encodeInt32(self.defaultCacheStorageTimeout, forKey: "dt") 27 | } 28 | 29 | public func isEqual(to: PreferencesEntry) -> Bool { 30 | if let to = to as? CacheStorageSettings { 31 | return self == to 32 | } else { 33 | return false 34 | } 35 | } 36 | 37 | public static func ==(lhs: CacheStorageSettings, rhs: CacheStorageSettings) -> Bool { 38 | return lhs.defaultCacheStorageTimeout == rhs.defaultCacheStorageTimeout 39 | } 40 | 41 | public func withUpdatedDefaultCacheStorageTimeout(_ defaultCacheStorageTimeout: Int32) -> CacheStorageSettings { 42 | return CacheStorageSettings(defaultCacheStorageTimeout: defaultCacheStorageTimeout) 43 | } 44 | } 45 | 46 | public func updateCacheStorageSettingsInteractively(accountManager: AccountManager, _ f: @escaping (CacheStorageSettings) -> CacheStorageSettings) -> Signal { 47 | return accountManager.transaction { transaction -> Void in 48 | transaction.updateSharedData(SharedDataKeys.cacheStorageSettings, { entry in 49 | let currentSettings: CacheStorageSettings 50 | if let entry = entry as? CacheStorageSettings { 51 | currentSettings = entry 52 | } else { 53 | currentSettings = CacheStorageSettings.defaultSettings 54 | } 55 | return f(currentSettings) 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /TelegramCore/CachedSentMediaReferences.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private let cachedSentMediaCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000) 11 | 12 | enum CachedSentMediaReferenceKey { 13 | case image(hash: Data) 14 | case file(hash: Data) 15 | 16 | var key: ValueBoxKey { 17 | switch self { 18 | case let .image(hash): 19 | let result = ValueBoxKey(length: 1 + hash.count) 20 | result.setUInt8(0, value: 0) 21 | hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in 22 | memcpy(result.memory.advanced(by: 1), bytes, hash.count) 23 | } 24 | return result 25 | case let .file(hash): 26 | let result = ValueBoxKey(length: 1 + hash.count) 27 | result.setUInt8(0, value: 1) 28 | hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in 29 | memcpy(result.memory.advanced(by: 1), bytes, hash.count) 30 | } 31 | return result 32 | } 33 | } 34 | } 35 | 36 | func cachedSentMediaReference(postbox: Postbox, key: CachedSentMediaReferenceKey) -> Signal { 37 | return postbox.transaction { transaction -> Media? in 38 | return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key)) as? Media 39 | } 40 | } 41 | 42 | func storeCachedSentMediaReference(transaction: Transaction, key: CachedSentMediaReferenceKey, media: Media) { 43 | transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media, collectionSpec: cachedSentMediaCollectionSpec) 44 | } 45 | -------------------------------------------------------------------------------- /TelegramCore/CanSendMessagesToPeer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public func canSendMessagesToPeer(_ peer: Peer) -> Bool { 9 | if peer is TelegramUser || peer is TelegramGroup { 10 | return !peer.isDeleted 11 | } else if let peer = peer as? TelegramSecretChat { 12 | return peer.embeddedState == .active 13 | } else if let peer = peer as? TelegramChannel { 14 | return peer.hasPermission(.sendMessages) 15 | } else { 16 | return false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TelegramCore/ChannelHistoryAvailabilitySettings.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import PostboxMac 3 | import SwiftSignalKitMac 4 | #else 5 | import Postbox 6 | import SwiftSignalKit 7 | #endif 8 | 9 | public enum ChannelHistoryAvailabilityError { 10 | case generic 11 | case hasNotPermissions 12 | } 13 | 14 | public func updateChannelHistoryAvailabilitySettingsInteractively(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, historyAvailableForNewMembers: Bool) -> Signal { 15 | return postbox.transaction { transaction -> Peer? in 16 | return transaction.getPeer(peerId) 17 | } 18 | |> introduceError(ChannelHistoryAvailabilityError.self) 19 | |> mapToSignal { peer in 20 | 21 | guard let peer = peer, let inputChannel = apiInputChannel(peer) else { 22 | return .fail(.generic) 23 | } 24 | 25 | return network.request(Api.functions.channels.togglePreHistoryHidden(channel: inputChannel, enabled: historyAvailableForNewMembers ? .boolFalse : .boolTrue)) 26 | |> `catch` { error -> Signal in 27 | if error.errorDescription == "CHAT_ADMIN_REQUIRED" { 28 | return .fail(.hasNotPermissions) 29 | } 30 | return .fail(.generic) 31 | } 32 | |> mapToSignal { updates -> Signal in 33 | accountStateManager.addUpdates(updates) 34 | return postbox.transaction { transaction -> Void in 35 | transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in 36 | if let currentData = currentData as? CachedChannelData { 37 | var flags = currentData.flags 38 | if historyAvailableForNewMembers { 39 | flags.insert(.preHistoryEnabled) 40 | } else { 41 | flags.remove(.preHistoryEnabled) 42 | } 43 | return currentData.withUpdatedFlags(flags) 44 | } else { 45 | return currentData 46 | } 47 | }) 48 | } |> introduceError(ChannelHistoryAvailabilityError.self) 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TelegramCore/ChannelMessageStateVersionAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ChannelMessageStateVersionAttribute: MessageAttribute { 9 | public let pts: Int32 10 | 11 | public init(pts: Int32) { 12 | self.pts = pts 13 | } 14 | 15 | required public init(decoder: PostboxDecoder) { 16 | self.pts = decoder.decodeInt32ForKey("p", orElse: 0) 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt32(self.pts, forKey: "p") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /TelegramCore/ChannelStats.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import PostboxMac 5 | #else 6 | import SwiftSignalKit 7 | import Postbox 8 | #endif 9 | 10 | public enum ChannelStatsUrlError { 11 | case generic 12 | } 13 | 14 | public func channelStatsUrl(postbox: Postbox, network: Network, peerId: PeerId, params: String, darkTheme: Bool) -> Signal { 15 | return postbox.transaction { transaction -> Api.InputPeer? in 16 | return transaction.getPeer(peerId).flatMap(apiInputPeer) 17 | } 18 | |> introduceError(ChannelStatsUrlError.self) 19 | |> mapToSignal { inputPeer -> Signal in 20 | guard let inputPeer = inputPeer else { 21 | return .fail(.generic) 22 | } 23 | var flags: Int32 = 0 24 | if darkTheme { 25 | flags |= (1 << 0) 26 | } 27 | return network.request(Api.functions.messages.getStatsURL(flags: flags, peer: inputPeer, params: params)) 28 | |> map { result -> String in 29 | switch result { 30 | case let .statsURL(url): 31 | return url 32 | } 33 | } 34 | |> `catch` { _ -> Signal in 35 | return .fail(.generic) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TelegramCore/ChatOnlineMembers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import PostboxMac 5 | #else 6 | import SwiftSignalKit 7 | import Postbox 8 | #endif 9 | 10 | public func chatOnlineMembers(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { 11 | return postbox.transaction { transaction -> Api.InputPeer? in 12 | return transaction.getPeer(peerId).flatMap(apiInputPeer) 13 | } 14 | |> mapToSignal { inputPeer -> Signal in 15 | guard let inputPeer = inputPeer else { 16 | return .single(0) 17 | } 18 | return network.request(Api.functions.messages.getOnlines(peer: inputPeer)) 19 | |> map { value -> Int32 in 20 | switch value { 21 | case let .chatOnlines(onlines): 22 | return onlines 23 | } 24 | } 25 | |> `catch` { _ -> Signal in 26 | return .single(0) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TelegramCore/CheckPeerChatServiceActions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func checkPeerChatServiceActions(postbox: Postbox, peerId: PeerId) -> Signal { 11 | return postbox.transaction { transaction -> Void in 12 | transaction.applyMarkUnread(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, value: false, interactive: true) 13 | 14 | if peerId.namespace == Namespaces.Peer.SecretChat { 15 | if let state = transaction.getPeerChatState(peerId) as? SecretChatState { 16 | let updatedState = secretChatCheckLayerNegotiationIfNeeded(transaction: transaction, peerId: peerId, state: state) 17 | if state != updatedState { 18 | transaction.setPeerChatState(peerId, state: updatedState) 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TelegramCore/CloudMediaResourceParameters.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum CloudMediaResourceLocation: Equatable { 4 | case photo(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String) 5 | case file(id: Int64, accessHash: Int64, fileReference: Data, thumbSize: String) 6 | case peerPhoto(peer: PeerReference, fullSize: Bool, volumeId: Int64, localId: Int64) 7 | case stickerPackThumbnail(packReference: StickerPackReference, volumeId: Int64, localId: Int64) 8 | } 9 | -------------------------------------------------------------------------------- /TelegramCore/Config/TelegramCore.xcconfig: -------------------------------------------------------------------------------- 1 | SWIFT_INCLUDE_PATHS = $(SRCROOT)/TelegramCore 2 | MODULEMAP_PRIVATE_FILE = $(SRCROOT)/TelegramCore/module.private.modulemap 3 | -------------------------------------------------------------------------------- /TelegramCore/ConfirmTwoStepRecoveryEmail.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import MtProtoKitMac 5 | #else 6 | import SwiftSignalKit 7 | import MtProtoKitDynamic 8 | #endif 9 | 10 | public enum ConfirmTwoStepRecoveryEmailError { 11 | case invalidEmail 12 | case invalidCode 13 | case flood 14 | case expired 15 | case generic 16 | } 17 | 18 | public func confirmTwoStepRecoveryEmail(network: Network, code: String) -> Signal { 19 | return network.request(Api.functions.account.confirmPasswordEmail(code: code), automaticFloodWait: false) 20 | |> mapError { error -> ConfirmTwoStepRecoveryEmailError in 21 | if error.errorDescription == "EMAIL_INVALID" { 22 | return .invalidEmail 23 | } else if error.errorDescription == "CODE_INVALID" { 24 | return .invalidCode 25 | } else if error.errorDescription == "EMAIL_HASH_EXPIRED" { 26 | return .expired 27 | } else if error.errorDescription.hasPrefix("FLOOD_WAIT") { 28 | return .flood 29 | } 30 | return .generic 31 | } 32 | |> ignoreValues 33 | } 34 | 35 | public enum ResendTwoStepRecoveryEmailError { 36 | case flood 37 | case generic 38 | } 39 | 40 | public func resendTwoStepRecoveryEmail(network: Network) -> Signal { 41 | return network.request(Api.functions.account.resendPasswordEmail(), automaticFloodWait: false) 42 | |> mapError { error -> ResendTwoStepRecoveryEmailError in 43 | if error.errorDescription.hasPrefix("FLOOD_WAIT") { 44 | return .flood 45 | } 46 | return .generic 47 | } 48 | |> ignoreValues 49 | } 50 | 51 | public enum CancelTwoStepRecoveryEmailError { 52 | case generic 53 | } 54 | 55 | public func cancelTwoStepRecoveryEmail(network: Network) -> Signal { 56 | return network.request(Api.functions.account.cancelPasswordEmail(), automaticFloodWait: false) 57 | |> mapError { _ -> CancelTwoStepRecoveryEmailError in 58 | return .generic 59 | } 60 | |> ignoreValues 61 | } 62 | -------------------------------------------------------------------------------- /TelegramCore/ConsumableContentMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ConsumableContentMessageAttribute: MessageAttribute { 9 | public let consumed: Bool 10 | 11 | public init(consumed: Bool) { 12 | self.consumed = consumed 13 | } 14 | 15 | required public init(decoder: PostboxDecoder) { 16 | self.consumed = decoder.decodeInt32ForKey("c", orElse: 0) != 0 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt32(self.consumed ? 1 : 0, forKey: "c") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /TelegramCore/ConsumablePersonalMentionMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ConsumablePersonalMentionMessageAttribute: MessageAttribute { 9 | public let consumed: Bool 10 | public let pending: Bool 11 | 12 | public init(consumed: Bool, pending: Bool) { 13 | self.consumed = consumed 14 | self.pending = pending 15 | } 16 | 17 | required public init(decoder: PostboxDecoder) { 18 | self.consumed = decoder.decodeInt32ForKey("c", orElse: 0) != 0 19 | self.pending = decoder.decodeInt32ForKey("p", orElse: 0) != 0 20 | } 21 | 22 | public func encode(_ encoder: PostboxEncoder) { 23 | encoder.encodeInt32(self.consumed ? 1 : 0, forKey: "c") 24 | encoder.encodeInt32(self.pending ? 1 : 0, forKey: "p") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TelegramCore/ConsumePersonalMessageAction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | final class ConsumePersonalMessageAction: PendingMessageActionData { 11 | init() { 12 | } 13 | 14 | init(decoder: PostboxDecoder) { 15 | } 16 | 17 | func encode(_ encoder: PostboxEncoder) { 18 | } 19 | 20 | func isEqual(to: PendingMessageActionData) -> Bool { 21 | if let _ = to as? ConsumePersonalMessageAction { 22 | return true 23 | } else { 24 | return false 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TelegramCore/ContactsSettings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct ContactsSettings: Equatable, PreferencesEntry { 9 | public var synchronizeContacts: Bool 10 | 11 | public static var defaultSettings: ContactsSettings { 12 | return ContactsSettings(synchronizeContacts: true) 13 | } 14 | 15 | public init(synchronizeContacts: Bool) { 16 | self.synchronizeContacts = synchronizeContacts 17 | } 18 | 19 | public init(decoder: PostboxDecoder) { 20 | self.synchronizeContacts = decoder.decodeInt32ForKey("synchronizeContacts", orElse: 0) != 0 21 | } 22 | 23 | public func encode(_ encoder: PostboxEncoder) { 24 | encoder.encodeInt32(self.synchronizeContacts ? 1 : 0, forKey: "synchronizeContacts") 25 | } 26 | 27 | public func isEqual(to: PreferencesEntry) -> Bool { 28 | if let to = to as? ContactsSettings { 29 | return self == to 30 | } else { 31 | return false 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TelegramCore/ContentPrivacySettings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public final class ContentPrivacySettings: PreferencesEntry, Equatable { 13 | public let enableSecretChatWebpagePreviews: Bool? 14 | 15 | public static var defaultSettings = ContentPrivacySettings(enableSecretChatWebpagePreviews: nil) 16 | 17 | public init(enableSecretChatWebpagePreviews: Bool?) { 18 | self.enableSecretChatWebpagePreviews = enableSecretChatWebpagePreviews 19 | } 20 | 21 | public init(decoder: PostboxDecoder) { 22 | self.enableSecretChatWebpagePreviews = decoder.decodeOptionalInt32ForKey("enableSecretChatWebpagePreviews").flatMap { $0 != 0 } 23 | } 24 | 25 | public func encode(_ encoder: PostboxEncoder) { 26 | if let enableSecretChatWebpagePreviews = self.enableSecretChatWebpagePreviews { 27 | encoder.encodeInt32(enableSecretChatWebpagePreviews ? 1 : 0, forKey: "enableSecretChatWebpagePreviews") 28 | } else { 29 | encoder.encodeNil(forKey: "enableSecretChatWebpagePreviews") 30 | } 31 | } 32 | 33 | public func withUpdatedEnableSecretChatWebpagePreviews(_ enableSecretChatWebpagePreviews: Bool) -> ContentPrivacySettings { 34 | return ContentPrivacySettings(enableSecretChatWebpagePreviews: enableSecretChatWebpagePreviews) 35 | } 36 | 37 | public func isEqual(to: PreferencesEntry) -> Bool { 38 | guard let to = to as? ContentPrivacySettings else { 39 | return false 40 | } 41 | 42 | return self == to 43 | } 44 | 45 | public static func ==(lhs: ContentPrivacySettings, rhs: ContentPrivacySettings) -> Bool { 46 | if lhs.enableSecretChatWebpagePreviews != rhs.enableSecretChatWebpagePreviews { 47 | return false 48 | } 49 | return true 50 | } 51 | } 52 | 53 | public func updateContentPrivacySettings(postbox: Postbox, _ f: @escaping (ContentPrivacySettings) -> ContentPrivacySettings) -> Signal { 54 | return postbox.transaction { transaction -> Void in 55 | var updated: ContentPrivacySettings? 56 | transaction.updatePreferencesEntry(key: PreferencesKeys.contentPrivacySettings, { current in 57 | if let current = current as? ContentPrivacySettings { 58 | updated = f(current) 59 | return updated 60 | } else { 61 | updated = f(ContentPrivacySettings.defaultSettings) 62 | return updated 63 | } 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /TelegramCore/ContentRequiresValidationMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ContentRequiresValidationMessageAttribute: MessageAttribute { 9 | public init() { 10 | } 11 | 12 | required public init(decoder: PostboxDecoder) { 13 | } 14 | 15 | public func encode(_ encoder: PostboxEncoder) { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TelegramCore/ConvertGroupToSupergroup.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public enum ConvertGroupToSupergroupError { 13 | case generic 14 | } 15 | 16 | public func convertGroupToSupergroup(account: Account, peerId: PeerId) -> Signal { 17 | return account.network.request(Api.functions.messages.migrateChat(chatId: peerId.id)) 18 | |> mapError { _ -> ConvertGroupToSupergroupError in 19 | return .generic 20 | } 21 | |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) 22 | |> mapToSignal { updates -> Signal in 23 | account.stateManager.addUpdates(updates) 24 | var createdPeerId: PeerId? 25 | for message in updates.messages { 26 | if apiMessagePeerId(message) != peerId { 27 | createdPeerId = apiMessagePeerId(message) 28 | break 29 | } 30 | } 31 | 32 | if let createdPeerId = createdPeerId { 33 | return account.postbox.multiplePeersView([createdPeerId]) 34 | |> filter { view in 35 | return view.peers[createdPeerId] != nil 36 | } 37 | |> take(1) 38 | |> map { _ in 39 | return createdPeerId 40 | } 41 | |> mapError { _ -> ConvertGroupToSupergroupError in 42 | return .generic 43 | } 44 | |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) 45 | } 46 | return .fail(.generic) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TelegramCore/CoreSettings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public final class CoreSettings: PreferencesEntry, Equatable { 13 | public let fastForward: Bool 14 | 15 | public static var defaultSettings = CoreSettings(fastForward: true) 16 | 17 | public init(fastForward: Bool) { 18 | self.fastForward = fastForward 19 | } 20 | 21 | public init(decoder: PostboxDecoder) { 22 | self.fastForward = decoder.decodeInt32ForKey("fastForward", orElse: 0) != 0 23 | } 24 | 25 | public func encode(_ encoder: PostboxEncoder) { 26 | encoder.encodeInt32(self.fastForward ? 1 : 0, forKey: "fastForward") 27 | } 28 | 29 | public func withUpdatedFastForward(_ fastForward: Bool) -> CoreSettings { 30 | return CoreSettings(fastForward: fastForward) 31 | } 32 | 33 | public func isEqual(to: PreferencesEntry) -> Bool { 34 | guard let to = to as? CoreSettings else { 35 | return false 36 | } 37 | 38 | return self == to 39 | } 40 | 41 | public static func ==(lhs: CoreSettings, rhs: CoreSettings) -> Bool { 42 | if lhs.fastForward != rhs.fastForward { 43 | return false 44 | } 45 | return true 46 | } 47 | } 48 | 49 | public func updateCoreSettings(postbox: Postbox, _ f: @escaping (CoreSettings) -> CoreSettings) -> Signal { 50 | return postbox.transaction { transaction -> Void in 51 | var updated: CoreSettings? 52 | transaction.updatePreferencesEntry(key: PreferencesKeys.coreSettings, { current in 53 | if let current = current as? CoreSettings { 54 | updated = f(current) 55 | return updated 56 | } else { 57 | updated = f(CoreSettings.defaultSettings) 58 | return updated 59 | } 60 | }) 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /TelegramCore/CreateGroup.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public enum CreateGroupError { 13 | case generic 14 | case privacy 15 | } 16 | 17 | public func createGroup(account: Account, title: String, peerIds: [PeerId]) -> Signal { 18 | return account.postbox.transaction { transaction -> Signal in 19 | var inputUsers: [Api.InputUser] = [] 20 | for peerId in peerIds { 21 | if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { 22 | inputUsers.append(inputUser) 23 | } else { 24 | return .single(nil) 25 | } 26 | } 27 | return account.network.request(Api.functions.messages.createChat(users: inputUsers, title: title)) 28 | |> mapError { error -> CreateGroupError in 29 | if error.errorDescription == "USERS_TOO_FEW" { 30 | return .privacy 31 | } 32 | return .generic 33 | } 34 | |> mapToSignal { updates -> Signal in 35 | account.stateManager.addUpdates(updates) 36 | if let message = updates.messages.first, let peerId = apiMessagePeerId(message) { 37 | return account.postbox.multiplePeersView([peerId]) 38 | |> filter { view in 39 | return view.peers[peerId] != nil 40 | } 41 | |> take(1) 42 | |> introduceError(CreateGroupError.self) 43 | |> map { _ in 44 | return peerId 45 | } 46 | } else { 47 | return .single(nil) 48 | } 49 | } 50 | } 51 | |> introduceError(CreateGroupError.self) 52 | |> switchToLatest 53 | } 54 | -------------------------------------------------------------------------------- /TelegramCore/Crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef __CRYPTO_H_ 2 | #define __CRYPTO_H_ 3 | 4 | #import 5 | 6 | NSData * _Nonnull CryptoMD5(const void *bytes, int count); 7 | NSData * _Nonnull CryptoSHA1(const void *bytes, int count); 8 | NSData * _Nonnull CryptoSHA256(const void *bytes, int count); 9 | NSData * _Nonnull CryptoSHA512(const void *bytes, int count); 10 | 11 | @interface IncrementalMD5 : NSObject 12 | 13 | - (instancetype _Nonnull)init; 14 | - (void)update:(NSData * _Nonnull)data; 15 | - (void)update:(const void * _Nonnull)bytes count:(int)count; 16 | - (NSData * _Nonnull)complete; 17 | 18 | @end 19 | 20 | NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /TelegramCore/Crypto.m: -------------------------------------------------------------------------------- 1 | #include "Crypto.h" 2 | 3 | #import 4 | 5 | NSData * _Nonnull CryptoMD5(const void *bytes, int count) { 6 | NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH]; 7 | CC_MD5(bytes, (CC_LONG)count, result.mutableBytes); 8 | return result; 9 | } 10 | 11 | NSData * _Nonnull CryptoSHA1(const void *bytes, int count) { 12 | NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA1_DIGEST_LENGTH]; 13 | CC_SHA1(bytes, (CC_LONG)count, result.mutableBytes); 14 | return result; 15 | } 16 | 17 | NSData * _Nonnull CryptoSHA256(const void *bytes, int count) { 18 | NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA256_DIGEST_LENGTH]; 19 | CC_SHA256(bytes, (CC_LONG)count, result.mutableBytes); 20 | return result; 21 | } 22 | 23 | NSData * _Nonnull CryptoSHA512(const void *bytes, int count) { 24 | NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_SHA512_DIGEST_LENGTH]; 25 | CC_SHA512(bytes, (CC_LONG)count, result.mutableBytes); 26 | return result; 27 | } 28 | 29 | @interface IncrementalMD5 () { 30 | CC_MD5_CTX _ctx; 31 | } 32 | 33 | @end 34 | 35 | @implementation IncrementalMD5 36 | 37 | - (instancetype _Nonnull)init { 38 | self = [super init]; 39 | if (self != nil) { 40 | CC_MD5_Init(&_ctx); 41 | } 42 | return self; 43 | } 44 | 45 | - (void)update:(NSData * _Nonnull)data { 46 | CC_MD5_Update(&_ctx, data.bytes, (CC_LONG)data.length); 47 | } 48 | 49 | - (void)update:(const void *)bytes count:(int)count { 50 | CC_MD5_Update(&_ctx, bytes, (CC_LONG)count); 51 | } 52 | 53 | - (NSData *)complete { 54 | NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH]; 55 | CC_MD5_Final(result.mutableBytes, &_ctx); 56 | return result; 57 | } 58 | 59 | @end 60 | 61 | NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data) { 62 | if (key.length != 32) { 63 | return nil; 64 | } 65 | if (iv.length != 16) { 66 | return nil; 67 | } 68 | NSMutableData *processedData = [[NSMutableData alloc] initWithLength:data.length]; 69 | size_t processedCount = 0; 70 | CCStatus status = CCCrypt(encrypt ? kCCEncrypt : kCCDecrypt, kCCAlgorithmAES128, 0, key.bytes, key.length, iv.bytes, data.bytes, data.length, processedData.mutableBytes, processedData.length, &processedCount); 71 | if (status != kCCSuccess) { 72 | return nil; 73 | } 74 | if (processedCount != (size_t)processedData.length) { 75 | return nil; 76 | } 77 | return processedData; 78 | } 79 | -------------------------------------------------------------------------------- /TelegramCore/DecryptedResourceData.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public func decryptedResourceData(data: MediaResourceData, resource: MediaResource, params: Any) -> Data? { 9 | guard data.complete else { 10 | return nil 11 | } 12 | guard let data = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.mappedRead]) else { 13 | return nil 14 | } 15 | if let resource = resource as? EncryptedMediaResource { 16 | return resource.decrypt(data: data, params: params) 17 | } else { 18 | return data 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /TelegramCore/DeepLinkInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | #else 5 | import SwiftSignalKit 6 | #endif 7 | 8 | public struct DeepLinkInfo { 9 | public let message: String 10 | public let entities: [MessageTextEntity] 11 | public let updateApp: Bool 12 | } 13 | 14 | public func getDeepLinkInfo(network: Network, path: String) -> Signal { 15 | return network.request(Api.functions.help.getDeepLinkInfo(path: path)) |> retryRequest 16 | |> map { value -> DeepLinkInfo? in 17 | switch value { 18 | case .deepLinkInfoEmpty: 19 | return nil 20 | case let .deepLinkInfo(flags, message, entities): 21 | return DeepLinkInfo(message: message, entities: entities != nil ? messageTextEntitiesFromApiEntities(entities!) : [], updateApp: (flags & (1 << 0)) != 0) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TelegramCore/DeleteMessages.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private func removeMessageMedia(message: Message, mediaBox: MediaBox) { 11 | for media in message.media { 12 | if let image = media as? TelegramMediaImage { 13 | let _ = mediaBox.removeCachedResources(Set(image.representations.map({ WrappedMediaResourceId($0.resource.id) }))).start() 14 | } else if let file = media as? TelegramMediaFile { 15 | let _ = mediaBox.removeCachedResources(Set(file.previewRepresentations.map({ WrappedMediaResourceId($0.resource.id) }))).start() 16 | let _ = mediaBox.removeCachedResources(Set([WrappedMediaResourceId(file.resource.id)])).start() 17 | } 18 | } 19 | } 20 | 21 | public func deleteMessages(transaction: Transaction, mediaBox: MediaBox, ids: [MessageId]) { 22 | for id in ids { 23 | if id.peerId.namespace == Namespaces.Peer.SecretChat { 24 | if let message = transaction.getMessage(id) { 25 | removeMessageMedia(message: message, mediaBox: mediaBox) 26 | } 27 | } 28 | } 29 | transaction.deleteMessages(ids) 30 | } 31 | 32 | public func clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId) { 33 | if peerId.namespace == Namespaces.Peer.SecretChat { 34 | transaction.withAllMessages(peerId: peerId, { message in 35 | removeMessageMedia(message: message, mediaBox: mediaBox) 36 | return true 37 | }) 38 | } 39 | transaction.clearHistory(peerId) 40 | } 41 | -------------------------------------------------------------------------------- /TelegramCore/DeserializeFunctionResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class FunctionDescription { 4 | let name: String 5 | let parameters: [(String, Any)] 6 | 7 | init(name: String, parameters: [(String, Any)]) { 8 | self.name = name 9 | self.parameters = parameters 10 | } 11 | } 12 | 13 | public final class DeserializeFunctionResponse { 14 | private let f: (Buffer) -> T? 15 | 16 | public init(_ f: @escaping (Buffer) -> T?) { 17 | self.f = f 18 | } 19 | 20 | public func parse(_ buffer: Buffer) -> T? { 21 | return self.f(buffer) 22 | } 23 | } 24 | 25 | protocol TypeConstructorDescription { 26 | func descriptionFields() -> (String, [(String, Any)]) 27 | } 28 | -------------------------------------------------------------------------------- /TelegramCore/EditedMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class EditedMessageAttribute: MessageAttribute { 9 | public let date: Int32 10 | 11 | init(date: Int32) { 12 | self.date = date 13 | } 14 | 15 | required public init(decoder: PostboxDecoder) { 16 | self.date = decoder.decodeInt32ForKey("d", orElse: 0) 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt32(self.date, forKey: "d") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /TelegramCore/Either.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Either { 4 | case left(value: Left) 5 | case right(value: Right) 6 | } 7 | -------------------------------------------------------------------------------- /TelegramCore/EncryptedMediaResource.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol EncryptedMediaResource { 4 | func decrypt(data: Data, params: Any) -> Data? 5 | } 6 | -------------------------------------------------------------------------------- /TelegramCore/ExportMessageLink.swift: -------------------------------------------------------------------------------- 1 | 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | 11 | public func exportMessageLink(account: Account, peerId: PeerId, messageId: MessageId) -> Signal { 12 | return account.postbox.transaction { transaction -> Peer? in 13 | return transaction.getPeer(peerId) 14 | } 15 | |> mapToSignal { peer -> Signal in 16 | if let peer = peer, let input = apiInputChannel(peer) { 17 | return account.network.request(Api.functions.channels.exportMessageLink(channel: input, id: messageId.id, grouped: .boolTrue)) |> mapError { _ in return } 18 | |> map { res in 19 | switch res { 20 | case let .exportedMessageLink(link, _): 21 | return link 22 | } 23 | } |> `catch` { _ -> Signal in 24 | return .single(nil) 25 | } 26 | } else { 27 | return .single(nil) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TelegramCore/ExportedInvitation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct ExportedInvitation: PostboxCoding, Equatable { 9 | public let link: String 10 | 11 | init(link: String) { 12 | self.link = link 13 | } 14 | 15 | public init(decoder: PostboxDecoder) { 16 | self.link = decoder.decodeStringForKey("l", orElse: "") 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeString(self.link, forKey: "l") 21 | } 22 | 23 | public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool { 24 | return lhs.link == rhs.link 25 | } 26 | } 27 | 28 | extension ExportedInvitation { 29 | init?(apiExportedInvite: Api.ExportedChatInvite) { 30 | switch apiExportedInvite { 31 | case .chatInviteEmpty: 32 | return nil 33 | case let .chatInviteExported(link): 34 | self = ExportedInvitation(link: link) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TelegramCore/FeaturedStickerPack.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct FeaturedStickerPackItemId { 9 | public let rawValue: MemoryBuffer 10 | public let packId: Int64 11 | 12 | init(_ rawValue: MemoryBuffer) { 13 | self.rawValue = rawValue 14 | assert(rawValue.length == 8) 15 | var idValue: Int64 = 0 16 | memcpy(&idValue, rawValue.memory, 8) 17 | self.packId = idValue 18 | } 19 | 20 | init(_ packId: Int64) { 21 | self.packId = packId 22 | var idValue: Int64 = packId 23 | self.rawValue = MemoryBuffer(memory: malloc(8)!, capacity: 8, length: 8, freeWhenDone: true) 24 | memcpy(self.rawValue.memory, &idValue, 8) 25 | } 26 | } 27 | 28 | public final class FeaturedStickerPackItem: OrderedItemListEntryContents { 29 | public let info: StickerPackCollectionInfo 30 | public let topItems: [StickerPackItem] 31 | public let unread: Bool 32 | 33 | init(info: StickerPackCollectionInfo, topItems: [StickerPackItem], unread: Bool) { 34 | self.info = info 35 | self.topItems = topItems 36 | self.unread = unread 37 | } 38 | 39 | public init(decoder: PostboxDecoder) { 40 | self.info = decoder.decodeObjectForKey("i") as! StickerPackCollectionInfo 41 | self.topItems = decoder.decodeObjectArrayForKey("t") 42 | self.unread = decoder.decodeInt32ForKey("u", orElse: 0) != 0 43 | } 44 | 45 | public func encode(_ encoder: PostboxEncoder) { 46 | encoder.encodeObject(self.info, forKey: "i") 47 | encoder.encodeObjectArray(self.topItems, forKey: "t") 48 | encoder.encodeInt32(self.unread ? 1 : 0, forKey: "u") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TelegramCore/FetchHttpResource.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public func fetchHttpResource(url: String) -> Signal { 13 | if let url = URL(string: url) { 14 | let signal = MTHttpRequestOperation.data(forHttpUrl: url)! 15 | return Signal { subscriber in 16 | subscriber.putNext(.reset) 17 | let disposable = signal.start(next: { next in 18 | let data = next as! Data 19 | let fetchResult: MediaResourceDataFetchResult = .dataPart(resourceOffset: 0, data: data, range: 0 ..< data.count, complete: true) 20 | subscriber.putNext(fetchResult) 21 | subscriber.putCompletion() 22 | }, error: { _ in 23 | subscriber.putError(.generic) 24 | }, completed: { 25 | }) 26 | 27 | return ActionDisposable { 28 | disposable?.dispose() 29 | } 30 | } 31 | } else { 32 | return .never() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TelegramCore/FetchSecretFileResource.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | func fetchSecretFileResource(account: Account, resource: SecretFileMediaResource, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { 13 | 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) 14 | } 15 | -------------------------------------------------------------------------------- /TelegramCore/FindChannelById.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import PostboxMac 5 | #else 6 | import SwiftSignalKit 7 | import Postbox 8 | #endif 9 | 10 | public func findChannelById(postbox: Postbox, network: Network, channelId: Int32) -> Signal { 11 | return network.request(Api.functions.channels.getChannels(id: [.inputChannel(channelId: channelId, accessHash: 0)])) 12 | |> map(Optional.init) 13 | |> `catch` { _ -> Signal in 14 | return .single(nil) 15 | } 16 | |> mapToSignal { result -> Signal in 17 | guard let result = result else { 18 | return .single(nil) 19 | } 20 | let chats: [Api.Chat] 21 | switch result { 22 | case let .chats(apiChats): 23 | chats = apiChats 24 | case let .chatsSlice(_, apiChats): 25 | chats = apiChats 26 | } 27 | guard let chat = chats.first else { 28 | return .single(nil) 29 | } 30 | guard let peer = parseTelegramGroupOrChannel(chat: chat) else { 31 | return .single(nil) 32 | } 33 | 34 | return postbox.transaction { transaction -> Peer? in 35 | updatePeers(transaction: transaction, peers: [peer], update: { _, updated in 36 | return updated 37 | }) 38 | return peer 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TelegramCore/ForwardGame.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func forwardGameWithScore(account: Account, messageId: MessageId, to peerId: PeerId) -> Signal { 11 | return account.postbox.transaction { transaction -> Signal in 12 | 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) { 13 | return account.network.request(Api.functions.messages.forwardMessages(flags: 1 << 8, fromPeer: fromInputPeer, id: [messageId.id], randomId: [arc4random64()], toPeer: toInputPeer)) 14 | |> map(Optional.init) 15 | |> `catch` { _ -> Signal in 16 | return .single(nil) 17 | } 18 | |> mapToSignal { updates -> Signal in 19 | if let updates = updates { 20 | account.stateManager.addUpdates(updates) 21 | } 22 | return .complete() 23 | } 24 | } 25 | return .complete() 26 | } |> switchToLatest 27 | } 28 | -------------------------------------------------------------------------------- /TelegramCore/ForwardSourceInfoAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ForwardSourceInfoAttribute: MessageAttribute { 9 | public let messageId: MessageId 10 | 11 | init(messageId: MessageId) { 12 | self.messageId = messageId 13 | } 14 | 15 | required public init(decoder: PostboxDecoder) { 16 | self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: decoder.decodeInt32ForKey("n", orElse: 0), id: decoder.decodeInt32ForKey("i", orElse: 0)) 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") 21 | encoder.encodeInt32(self.messageId.namespace, forKey: "n") 22 | encoder.encodeInt32(self.messageId.id, forKey: "i") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TelegramCore/GlobalTelegramCoreConfiguration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class GlobalTelegramCoreConfiguration { 4 | public static var readMessages: Bool = true 5 | } 6 | -------------------------------------------------------------------------------- /TelegramCore/GroupFeedPeers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func availableGroupFeedPeers(postbox: Postbox, network: Network, groupId: PeerGroupId) -> Signal<[(Peer, Bool)], NoError> { 11 | /*feed*/ 12 | return .single([]) 13 | /*return network.request(Api.functions.channels.getFeedSources(flags: 0, feedId: groupId.rawValue, hash: 0)) 14 | |> retryRequest 15 | |> mapToSignal { result -> Signal<[(Peer, Bool)], NoError> in 16 | return postbox.transaction { transaction -> [(Peer, Bool)] in 17 | switch result { 18 | case .feedSourcesNotModified: 19 | return [] 20 | case let .feedSources(_, newlyJoinedFeed, feeds, chats, users): 21 | var includedPeerIds = Set() 22 | var excludedPeerIds = Set() 23 | for feedsInfo in feeds { 24 | switch feedsInfo { 25 | case let .feedBroadcasts(feedId, channels): 26 | if feedId == groupId.rawValue { 27 | for id in channels { 28 | includedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) 29 | } 30 | } 31 | case let .feedBroadcastsUngrouped(channels): 32 | for id in channels { 33 | excludedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) 34 | } 35 | } 36 | } 37 | var peers: [(Peer, Bool)] = [] 38 | for peerId in includedPeerIds { 39 | if let peer = transaction.getPeer(peerId) { 40 | peers.append((peer, true)) 41 | } 42 | } 43 | for peerId in excludedPeerIds { 44 | if let peer = transaction.getPeer(peerId) { 45 | peers.append((peer, false)) 46 | } 47 | } 48 | return peers 49 | } 50 | } 51 | }*/ 52 | } 53 | -------------------------------------------------------------------------------- /TelegramCore/GroupReturnAndLeft.swift: -------------------------------------------------------------------------------- 1 | 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | 13 | public func returnGroup(account: Account, peerId: PeerId) -> Signal { 14 | return account.postbox.loadedPeerWithId(account.peerId) 15 | |> take(1) 16 | |> mapToSignal { peer -> Signal in 17 | if let inputUser = apiInputUser(peer) { 18 | return account.network.request(Api.functions.messages.addChatUser(chatId: peerId.id, userId: inputUser, fwdLimit: 50)) 19 | |> retryRequest 20 | |> mapToSignal { updates -> Signal in 21 | account.stateManager.addUpdates(updates) 22 | return .complete() 23 | } 24 | } else { 25 | return .complete() 26 | } 27 | } 28 | } 29 | 30 | public func leftGroup(account: Account, peerId: PeerId) -> Signal { 31 | return account.postbox.loadedPeerWithId(account.peerId) 32 | |> take(1) 33 | |> mapToSignal { peer -> Signal in 34 | if let inputUser = apiInputUser(peer) { 35 | return account.network.request(Api.functions.messages .deleteChatUser(chatId: peerId.id, userId: inputUser)) 36 | |> retryRequest 37 | |> mapToSignal { updates -> Signal in 38 | account.stateManager.addUpdates(updates) 39 | return .complete() 40 | } 41 | } else { 42 | return .complete() 43 | } 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /TelegramCore/GroupsInCommon.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[PeerId], NoError> { 11 | return account.postbox.transaction { transaction -> Signal<[PeerId], NoError> in 12 | if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { 13 | return account.network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: 0, limit: 100)) 14 | |> retryRequest 15 | |> mapToSignal { result -> Signal<[PeerId], NoError> in 16 | let chats: [Api.Chat] 17 | switch result { 18 | case let .chats(chats: apiChats): 19 | chats = apiChats 20 | case let .chatsSlice(count: _, chats: apiChats): 21 | chats = apiChats 22 | } 23 | 24 | return account.postbox.transaction { transaction -> [PeerId] in 25 | var peers:[Peer] = [] 26 | for chat in chats { 27 | if let peer = parseTelegramGroupOrChannel(chat: chat) { 28 | peers.append(peer) 29 | } 30 | } 31 | updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer? in 32 | return updated 33 | }) 34 | return peers.map {$0.id} 35 | } 36 | } 37 | } else { 38 | return .single([]) 39 | } 40 | } |> switchToLatest 41 | } 42 | -------------------------------------------------------------------------------- /TelegramCore/ImportContact.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import PostboxMac 3 | import SwiftSignalKitMac 4 | #else 5 | import Postbox 6 | import SwiftSignalKit 7 | #endif 8 | 9 | public func importContact(account:Account, firstName: String, lastName: String, phoneNumber: String) -> Signal { 10 | 11 | let input = Api.InputContact.inputPhoneContact(clientId: 1, phone: phoneNumber, firstName: firstName, lastName: lastName) 12 | 13 | return account.network.request(Api.functions.contacts.importContacts(contacts: [input])) 14 | |> map(Optional.init) 15 | |> `catch` { _ -> Signal in 16 | return .single(nil) 17 | } 18 | |> mapToSignal { result -> Signal in 19 | return account.postbox.transaction { transaction -> PeerId? in 20 | if let result = result { 21 | switch result { 22 | case let .importedContacts(_, _, _, users): 23 | if let first = users.first { 24 | let user = TelegramUser(user: first) 25 | let peerId = user.id 26 | updatePeers(transaction: transaction, peers: [user], update: { _, updated in 27 | return updated 28 | }) 29 | var peerIds = transaction.getContactPeerIds() 30 | if !peerIds.contains(peerId) { 31 | peerIds.insert(peerId) 32 | transaction.replaceContactPeerIds(peerIds) 33 | } 34 | return peerId 35 | } 36 | } 37 | } 38 | return nil 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TelegramCore/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TelegramCore/InitializeAccountAfterLogin.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import PostboxMac 5 | #else 6 | import SwiftSignalKit 7 | import Postbox 8 | #endif 9 | 10 | func initializedAppSettingsAfterLogin(transaction: Transaction, appVersion: String, syncContacts: Bool) { 11 | updateAppChangelogState(transaction: transaction, { state in 12 | var state = state 13 | state.checkedVersion = appVersion 14 | state.previousVersion = appVersion 15 | return state 16 | }) 17 | transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { _ in 18 | return ContactsSettings(synchronizeContacts: syncContacts) 19 | }) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /TelegramCore/InlineBotMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class InlineBotMessageAttribute: MessageAttribute { 9 | public let peerId: PeerId? 10 | public let title: String? 11 | 12 | public var associatedPeerIds: [PeerId] { 13 | if let peerId = self.peerId { 14 | return [peerId] 15 | } else { 16 | return [] 17 | } 18 | } 19 | 20 | init(peerId: PeerId?, title: String?) { 21 | self.peerId = peerId 22 | self.title = title 23 | } 24 | 25 | required public init(decoder: PostboxDecoder) { 26 | if let peerId = decoder.decodeOptionalInt64ForKey("i") { 27 | self.peerId = PeerId(peerId) 28 | } else { 29 | self.peerId = nil 30 | } 31 | self.title = decoder.decodeOptionalStringForKey("t") 32 | } 33 | 34 | public func encode(_ encoder: PostboxEncoder) { 35 | if let peerId = self.peerId { 36 | encoder.encodeInt64(peerId.toInt64(), forKey: "i") 37 | } else { 38 | encoder.encodeNil(forKey: "i") 39 | } 40 | if let title = self.title { 41 | encoder.encodeString(title, forKey: "t") 42 | } else { 43 | encoder.encodeNil(forKey: "t") 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TelegramCore/InteractivePhoneFormatter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import TelegramCorePrivateModule 3 | 4 | public final class InteractivePhoneFormatter { 5 | private let formatter = NBAsYouTypeFormatter(regionCode: "US")! 6 | 7 | public init() { 8 | } 9 | 10 | public func updateText(_ text: String) -> (String?, String) { 11 | self.formatter.clear() 12 | let string = self.formatter.inputString(text) 13 | return (self.formatter.regionPrefix, string ?? "") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TelegramCore/LocalizationPreview.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import PostboxMac 3 | import SwiftSignalKitMac 4 | import MtProtoKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | import MtProtoKitDynamic 9 | #endif 10 | 11 | public enum RequestLocalizationPreviewError { 12 | case generic 13 | } 14 | 15 | public func requestLocalizationPreview(network: Network, identifier: String) -> Signal { 16 | return network.request(Api.functions.langpack.getLanguage(langPack: "", langCode: identifier)) 17 | |> mapError { _ -> RequestLocalizationPreviewError in 18 | return .generic 19 | } 20 | |> map { language -> LocalizationInfo in 21 | return LocalizationInfo(apiLanguage: language) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TelegramCore/LoggedOutAccountAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class LoggedOutAccountAttribute: AccountRecordAttribute { 9 | public init() { 10 | } 11 | 12 | public init(decoder: PostboxDecoder) { 13 | } 14 | 15 | public func encode(_ encoder: PostboxEncoder) { 16 | } 17 | 18 | public func isEqual(to: AccountRecordAttribute) -> Bool { 19 | return to is LoggedOutAccountAttribute 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /TelegramCore/MD5.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import TelegramCorePrivateModule 3 | #if os(macOS) 4 | import PostboxMac 5 | #else 6 | import Postbox 7 | #endif 8 | 9 | public extension MemoryBuffer { 10 | public func md5Digest() -> Data { 11 | return CryptoMD5(self.memory, Int32(self.length)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TelegramCore/ManagedAppConfigurationUpdates.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | func managedAppConfigurationUpdates(postbox: Postbox, network: Network) -> Signal { 13 | let poll = Signal { subscriber in 14 | return (network.request(Api.functions.help.getAppConfig()) 15 | |> retryRequest 16 | |> mapToSignal { result -> Signal in 17 | return postbox.transaction { transaction -> Void in 18 | if let data = JSON(apiJson: result) { 19 | updateAppConfiguration(transaction: transaction, { configuration -> AppConfiguration in 20 | var configuration = configuration 21 | configuration.data = data 22 | return configuration 23 | }) 24 | } 25 | } 26 | }).start() 27 | } 28 | return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart 29 | } 30 | -------------------------------------------------------------------------------- /TelegramCore/ManagedAutodownloadSettingsUpdates.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | func managedAutodownloadSettingsUpdates(accountManager: AccountManager, network: Network) -> Signal { 13 | let poll = Signal { subscriber in 14 | return (network.request(Api.functions.account.getAutoDownloadSettings()) 15 | |> retryRequest 16 | |> mapToSignal { result -> Signal in 17 | return updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in 18 | return AutodownloadSettings(apiAutodownloadSettings: result) 19 | }) 20 | }).start() 21 | } 22 | return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart 23 | } 24 | 25 | public enum SavedAutodownloadPreset { 26 | case low 27 | case medium 28 | case high 29 | } 30 | 31 | public func saveAutodownloadSettings(account: Account, preset: SavedAutodownloadPreset, settings: AutodownloadPresetSettings) -> Signal { 32 | var flags: Int32 = 0 33 | switch preset { 34 | case .low: 35 | flags |= (1 << 0) 36 | case .high: 37 | flags |= (1 << 1) 38 | default: 39 | break 40 | } 41 | return account.network.request(Api.functions.account.saveAutoDownloadSettings(flags: flags, settings: apiAutodownloadPresetSettings(settings))) 42 | |> `catch` { _ -> Signal in 43 | return .complete() 44 | } 45 | |> mapToSignal { _ -> Signal in 46 | return .complete() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TelegramCore/ManagedChatListHoles.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private final class ManagedChatListHolesState { 11 | private var holeDisposables: [ChatListHolesEntry: Disposable] = [:] 12 | 13 | func clearDisposables() -> [Disposable] { 14 | let disposables = Array(self.holeDisposables.values) 15 | self.holeDisposables.removeAll() 16 | return disposables 17 | } 18 | 19 | func update(entries: Set) -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) { 20 | var removed: [Disposable] = [] 21 | var added: [ChatListHolesEntry: MetaDisposable] = [:] 22 | 23 | for (entry, disposable) in self.holeDisposables { 24 | if !entries.contains(entry) { 25 | removed.append(disposable) 26 | self.holeDisposables.removeValue(forKey: entry) 27 | } 28 | } 29 | 30 | for entry in entries { 31 | if self.holeDisposables[entry] == nil { 32 | let disposable = MetaDisposable() 33 | self.holeDisposables[entry] = disposable 34 | added[entry] = disposable 35 | } 36 | } 37 | 38 | return (removed, added) 39 | } 40 | } 41 | 42 | func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: PeerId) -> Signal { 43 | return Signal { _ in 44 | let state = Atomic(value: ManagedChatListHolesState()) 45 | 46 | let disposable = postbox.chatListHolesView().start(next: { view in 47 | let (removed, added) = state.with { state -> (removed: [Disposable], added: [ChatListHolesEntry: MetaDisposable]) in 48 | return state.update(entries: view.entries) 49 | } 50 | 51 | for disposable in removed { 52 | disposable.dispose() 53 | } 54 | 55 | for (entry, disposable) in added { 56 | disposable.set(fetchChatListHole(postbox: postbox, network: network, accountPeerId: accountPeerId, groupId: entry.groupId, hole: entry.hole).start()) 57 | } 58 | }) 59 | 60 | return ActionDisposable { 61 | disposable.dispose() 62 | for disposable in state.with({ state -> [Disposable] in 63 | state.clearDisposables() 64 | }) { 65 | disposable.dispose() 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /TelegramCore/ManagedNotificationSettingsBehaviors.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | func managedNotificationSettingsBehaviors(postbox: Postbox) -> Signal { 11 | return postbox.combinedView(keys: [.peerNotificationSettingsBehaviorTimestampView]) 12 | |> mapToSignal { views -> Signal in 13 | guard let view = views.views[.peerNotificationSettingsBehaviorTimestampView] as? PeerNotificationSettingsBehaviorTimestampView else { 14 | return .complete() 15 | } 16 | guard let earliestTimestamp = view.earliestTimestamp else { 17 | return .complete() 18 | } 19 | 20 | let checkSignal = postbox.transaction { transaction -> Void in 21 | let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) 22 | for (peerId, notificationSettings) in transaction.getPeerIdsAndNotificationSettingsWithBehaviorTimestampLessThanOrEqualTo(timestamp) { 23 | if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { 24 | if case let .muted(untilTimestamp) = notificationSettings.muteState, untilTimestamp <= timestamp { 25 | transaction.updateCurrentPeerNotificationSettings([peerId: notificationSettings.withUpdatedMuteState(.unmuted)]) 26 | } 27 | } 28 | } 29 | } 30 | |> ignoreValues 31 | 32 | let timeout = earliestTimestamp - Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) 33 | if timeout <= 0 { 34 | return checkSignal 35 | } else { 36 | return checkSignal |> delay(Double(timeout), queue: .mainQueue()) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TelegramCore/ManagedServiceViews.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | func managedServiceViews(accountPeerId: PeerId, network: Network, postbox: Postbox, stateManager: AccountStateManager, pendingMessageManager: PendingMessageManager) -> Signal { 11 | return Signal { _ in 12 | let disposable = DisposableSet() 13 | disposable.add(managedMessageHistoryHoles(accountPeerId: accountPeerId, network: network, postbox: postbox).start()) 14 | disposable.add(managedChatListHoles(network: network, postbox: postbox, accountPeerId: accountPeerId).start()) 15 | disposable.add(managedSynchronizePeerReadStates(network: network, postbox: postbox, stateManager: stateManager).start()) 16 | disposable.add(managedSynchronizeGroupMessageStats(network: network, postbox: postbox, stateManager: stateManager).start()) 17 | 18 | return disposable 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /TelegramCore/ManagedVoipConfigurationUpdates.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | func managedVoipConfigurationUpdates(postbox: Postbox, network: Network) -> Signal { 13 | let poll = Signal { subscriber in 14 | return (network.request(Api.functions.phone.getCallConfig()) 15 | |> retryRequest 16 | |> mapToSignal { result -> Signal in 17 | return postbox.transaction { transaction -> Void in 18 | switch result { 19 | case let .dataJSON(data): 20 | updateVoipConfiguration(transaction: transaction, { configuration in 21 | var configuration = configuration 22 | configuration.serializedData = data 23 | return configuration 24 | }) 25 | } 26 | } 27 | }).start() 28 | } 29 | return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart 30 | } 31 | -------------------------------------------------------------------------------- /TelegramCore/MediaResourceApiUtils.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension SecretChatFileReference { 4 | func resource(key: SecretFileEncryptionKey, decryptedSize: Int32) -> SecretFileMediaResource { 5 | return SecretFileMediaResource(fileId: self.id, accessHash: self.accessHash, containerSize: self.size, decryptedSize: decryptedSize, datacenterId: Int(self.datacenterId), key: key) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /TelegramCore/MediaResourceNetworkStatsTag.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import PostboxMac 3 | #else 4 | import Postbox 5 | #endif 6 | 7 | public enum MediaResourceStatsCategory { 8 | case generic 9 | case image 10 | case video 11 | case audio 12 | case file 13 | case call 14 | } 15 | 16 | public final class TelegramMediaResourceFetchTag: MediaResourceFetchTag { 17 | public let statsCategory: MediaResourceStatsCategory 18 | 19 | public init(statsCategory: MediaResourceStatsCategory) { 20 | self.statsCategory = statsCategory 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /TelegramCore/MemoryBufferExtensions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public extension MemoryBuffer { 9 | public convenience init(_ buffer: Buffer) { 10 | let memory = malloc(Int(buffer.size))! 11 | memcpy(memory, buffer.data, Int(buffer.size)) 12 | self.init(memory: memory, capacity: Int(buffer.size), length: Int(buffer.size), freeWhenDone: true) 13 | } 14 | } 15 | 16 | extension Buffer { 17 | convenience init(bufferNoCopy: MemoryBuffer) { 18 | self.init(memory: bufferNoCopy.memory, size: bufferNoCopy.length, capacity: bufferNoCopy.length, freeWhenDone: false) 19 | } 20 | 21 | convenience init(buffer: MemoryBuffer) { 22 | let memory = malloc(buffer.length)! 23 | memcpy(memory, buffer.memory, buffer.length) 24 | self.init(memory: memory, size: buffer.length, capacity: buffer.length, freeWhenDone: true) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TelegramCore/MonotonicTime.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int64_t MonotonicGetBootTimestamp(); 4 | int64_t MonotonicGetUptime(); 5 | -------------------------------------------------------------------------------- /TelegramCore/MonotonicTime.m: -------------------------------------------------------------------------------- 1 | #import "MonotonicTime.h" 2 | 3 | #include 4 | 5 | int64_t MonotonicGetBootTimestamp() { 6 | struct timeval boottime; 7 | int mib[2] = {CTL_KERN, KERN_BOOTTIME}; 8 | size_t size = sizeof(boottime); 9 | int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); 10 | if (rc != 0) { 11 | return 0; 12 | } 13 | return boottime.tv_sec * 1000000 + boottime.tv_usec; 14 | } 15 | 16 | int64_t MonotonicGetUptime() { 17 | int64_t before_now; 18 | int64_t after_now; 19 | struct timeval now; 20 | 21 | after_now = MonotonicGetBootTimestamp(); 22 | do { 23 | before_now = after_now; 24 | gettimeofday(&now, NULL); 25 | after_now = MonotonicGetBootTimestamp(); 26 | } while (after_now != before_now); 27 | 28 | return now.tv_sec * 1000000 + now.tv_usec - before_now; 29 | } 30 | -------------------------------------------------------------------------------- /TelegramCore/MonotonicTime.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | import TelegramCorePrivateModule 4 | 5 | public struct MonotonicTime { 6 | public func getBootTimestamp() -> Int64 { 7 | return MonotonicGetBootTimestamp() 8 | } 9 | 10 | public func getUptime() -> Int64 { 11 | return MonotonicGetUptime() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TelegramCore/NetworkLogging.h: -------------------------------------------------------------------------------- 1 | #ifndef Telegram_NetworkLogging_h 2 | #define Telegram_NetworkLogging_h 3 | 4 | #import 5 | 6 | void NetworkRegisterLoggingFunction(); 7 | void NetworkSetLoggingEnabled(bool); 8 | 9 | void setBridgingTraceFunction(void (*)(NSString *, NSString *)); 10 | void setBridgingShortTraceFunction(void (*)(NSString *, NSString *)); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /TelegramCore/NetworkLogging.m: -------------------------------------------------------------------------------- 1 | #import "NetworkLogging.h" 2 | 3 | #import 4 | 5 | #if TARGET_OS_IOS 6 | # import 7 | #else 8 | # import 9 | #endif 10 | 11 | static void (*bridgingTrace)(NSString *, NSString *); 12 | void setBridgingTraceFunction(void (*f)(NSString *, NSString *)) { 13 | bridgingTrace = f; 14 | } 15 | 16 | static void (*bridgingShortTrace)(NSString *, NSString *); 17 | void setBridgingShortTraceFunction(void (*f)(NSString *, NSString *)) { 18 | bridgingShortTrace = f; 19 | } 20 | 21 | static void TGTelegramLoggingFunction(NSString *format, va_list args) { 22 | if (bridgingTrace) { 23 | bridgingTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); 24 | } 25 | } 26 | 27 | static void TGTelegramShortLoggingFunction(NSString *format, va_list args) { 28 | if (bridgingShortTrace) { 29 | bridgingShortTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); 30 | } 31 | } 32 | 33 | void NetworkRegisterLoggingFunction() { 34 | static dispatch_once_t onceToken; 35 | dispatch_once(&onceToken, ^{ 36 | MTLogSetLoggingFunction(&TGTelegramLoggingFunction); 37 | MTLogSetShortLoggingFunction(&TGTelegramShortLoggingFunction); 38 | }); 39 | } 40 | 41 | void NetworkSetLoggingEnabled(bool value) { 42 | MTLogSetEnabled(value); 43 | } 44 | -------------------------------------------------------------------------------- /TelegramCore/NotificationInfoMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct NotificationInfoMessageAttributeFlags: OptionSet { 9 | public var rawValue: Int32 10 | 11 | public init(rawValue: Int32) { 12 | self.rawValue = rawValue 13 | } 14 | 15 | public init() { 16 | self.rawValue = 0 17 | } 18 | 19 | public static let muted = NotificationInfoMessageAttributeFlags(rawValue: 1) 20 | public static let personal = NotificationInfoMessageAttributeFlags(rawValue: 2) 21 | 22 | } 23 | 24 | public class NotificationInfoMessageAttribute: MessageAttribute { 25 | public let flags: NotificationInfoMessageAttributeFlags 26 | 27 | public init(flags: NotificationInfoMessageAttributeFlags) { 28 | self.flags = flags 29 | } 30 | 31 | required public init(decoder: PostboxDecoder) { 32 | self.flags = NotificationInfoMessageAttributeFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) 33 | } 34 | 35 | public func encode(_ encoder: PostboxEncoder) { 36 | encoder.encodeInt32(self.flags.rawValue, forKey: "f") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TelegramCore/OutgoingChatContextResultMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class OutgoingChatContextResultMessageAttribute: MessageAttribute { 9 | public let queryId: Int64 10 | public let id: String 11 | public let hideVia: Bool 12 | 13 | init(queryId: Int64, id: String, hideVia: Bool) { 14 | self.queryId = queryId 15 | self.id = id 16 | self.hideVia = hideVia 17 | } 18 | 19 | required public init(decoder: PostboxDecoder) { 20 | self.queryId = decoder.decodeInt64ForKey("q", orElse: 0) 21 | self.id = decoder.decodeStringForKey("i", orElse: "") 22 | self.hideVia = decoder.decodeBoolForKey("v", orElse: false) 23 | } 24 | 25 | public func encode(_ encoder: PostboxEncoder) { 26 | encoder.encodeInt64(self.queryId, forKey: "q") 27 | encoder.encodeString(self.id, forKey: "i") 28 | encoder.encodeBool(self.hideVia, forKey: "v") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TelegramCore/OutgoingContentInfoMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct OutgoingContentInfoFlags: OptionSet { 9 | public var rawValue: Int32 10 | 11 | public init() { 12 | self.rawValue = 0 13 | } 14 | 15 | public init(rawValue: Int32) { 16 | self.rawValue = rawValue 17 | } 18 | 19 | public static let disableLinkPreviews = OutgoingContentInfoFlags(rawValue: 1 << 0) 20 | } 21 | 22 | public class OutgoingContentInfoMessageAttribute: MessageAttribute { 23 | public let flags: OutgoingContentInfoFlags 24 | 25 | public init(flags: OutgoingContentInfoFlags) { 26 | self.flags = flags 27 | } 28 | 29 | required public init(decoder: PostboxDecoder) { 30 | self.flags = OutgoingContentInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) 31 | } 32 | 33 | public func encode(_ encoder: PostboxEncoder) { 34 | encoder.encodeInt32(self.flags.rawValue, forKey: "f") 35 | } 36 | 37 | public func withUpdatedFlags(_ flags: OutgoingContentInfoFlags) -> OutgoingContentInfoMessageAttribute { 38 | return OutgoingContentInfoMessageAttribute(flags: flags) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TelegramCore/OutgoingMessageInfoAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct OutgoingMessageInfoFlags: OptionSet { 9 | public var rawValue: Int32 10 | 11 | public init() { 12 | self.rawValue = 0 13 | } 14 | 15 | public init(rawValue: Int32) { 16 | self.rawValue = rawValue 17 | } 18 | 19 | public static var transformedMedia = OutgoingMessageInfoFlags(rawValue: 1 << 0) 20 | } 21 | 22 | public class OutgoingMessageInfoAttribute: MessageAttribute { 23 | public let uniqueId: Int64 24 | public let flags: OutgoingMessageInfoFlags 25 | public let acknowledged: Bool 26 | 27 | init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool) { 28 | self.uniqueId = uniqueId 29 | self.flags = flags 30 | self.acknowledged = acknowledged 31 | } 32 | 33 | required public init(decoder: PostboxDecoder) { 34 | self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0) 35 | self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) 36 | self.acknowledged = decoder.decodeInt32ForKey("ack", orElse: 0) != 0 37 | } 38 | 39 | public func encode(_ encoder: PostboxEncoder) { 40 | encoder.encodeInt64(self.uniqueId, forKey: "u") 41 | encoder.encodeInt32(self.flags.rawValue, forKey: "f") 42 | encoder.encodeInt32(self.acknowledged ? 1 : 0, forKey: "ack") 43 | } 44 | 45 | public func withUpdatedFlags(_ flags: OutgoingMessageInfoFlags) -> OutgoingMessageInfoAttribute { 46 | return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged) 47 | } 48 | 49 | public func withUpdatedAcknowledged(_ acknowledged: Bool) -> OutgoingMessageInfoAttribute { 50 | return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged) 51 | } 52 | } 53 | 54 | public extension Message { 55 | public var isSentOrAcknowledged: Bool { 56 | if self.flags.contains(.Failed) { 57 | return false 58 | } else if self.flags.isSending { 59 | for attribute in self.attributes { 60 | if let attribute = attribute as? OutgoingMessageInfoAttribute { 61 | if attribute.acknowledged { 62 | return true 63 | } 64 | } 65 | } 66 | return false 67 | } else { 68 | return true 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TelegramCore/PeerAccessRestrictionInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class PeerAccessRestrictionInfo: PostboxCoding, Equatable { 9 | public let reason: String 10 | 11 | init(reason: String) { 12 | self.reason = reason 13 | } 14 | 15 | public init(decoder: PostboxDecoder) { 16 | self.reason = decoder.decodeStringForKey("rsn", orElse: "") 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeString(self.reason, forKey: "rsn") 21 | } 22 | 23 | public static func ==(lhs: PeerAccessRestrictionInfo, rhs: PeerAccessRestrictionInfo) -> Bool { 24 | return lhs.reason == rhs.reason 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TelegramCore/PeerCommands.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public struct PeerCommand: Equatable { 11 | public let peer: Peer 12 | public let command: BotCommand 13 | 14 | public static func ==(lhs: PeerCommand, rhs: PeerCommand) -> Bool { 15 | return lhs.peer.isEqual(rhs.peer) && lhs.command == rhs.command 16 | } 17 | } 18 | 19 | public struct PeerCommands: Equatable { 20 | public let commands: [PeerCommand] 21 | 22 | public static func ==(lhs: PeerCommands, rhs: PeerCommands) -> Bool { 23 | return lhs.commands == rhs.commands 24 | } 25 | } 26 | 27 | public func peerCommands(account: Account, id: PeerId) -> Signal { 28 | return account.postbox.peerView(id: id) |> map { view -> PeerCommands in 29 | if let cachedUserData = view.cachedData as? CachedUserData { 30 | if let botInfo = cachedUserData.botInfo { 31 | if let botPeer = view.peers[id] { 32 | var commands: [PeerCommand] = [] 33 | for command in botInfo.commands { 34 | commands.append(PeerCommand(peer: botPeer, command: command)) 35 | } 36 | return PeerCommands(commands: commands) 37 | } 38 | } 39 | return PeerCommands(commands: []) 40 | } 41 | else if let cachedGroupData = view.cachedData as? CachedGroupData { 42 | var commands: [PeerCommand] = [] 43 | for cachedBotInfo in cachedGroupData.botInfos { 44 | if let botPeer = view.peers[cachedBotInfo.peerId] { 45 | for command in cachedBotInfo.botInfo.commands { 46 | commands.append(PeerCommand(peer: botPeer, command: command)) 47 | } 48 | } 49 | } 50 | return PeerCommands(commands: commands) 51 | } else if let cachedChannelData = view.cachedData as? CachedChannelData { 52 | var commands: [PeerCommand] = [] 53 | for cachedBotInfo in cachedChannelData.botInfos { 54 | if let botPeer = view.peers[cachedBotInfo.peerId] { 55 | for command in cachedBotInfo.botInfo.commands { 56 | commands.append(PeerCommand(peer: botPeer, command: command)) 57 | } 58 | } 59 | } 60 | return PeerCommands(commands: commands) 61 | } else { 62 | return PeerCommands(commands: []) 63 | } 64 | } 65 | |> distinctUntilChanged 66 | } 67 | -------------------------------------------------------------------------------- /TelegramCore/PeerGroupMessageStateVersionAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class PeerGroupMessageStateVersionAttribute: MessageAttribute { 9 | public let stateIndex: Int32 10 | 11 | public init(stateIndex: Int32) { 12 | self.stateIndex = stateIndex 13 | } 14 | 15 | required public init(decoder: PostboxDecoder) { 16 | self.stateIndex = decoder.decodeInt32ForKey("p", orElse: 0) 17 | } 18 | 19 | public func encode(_ encoder: PostboxEncoder) { 20 | encoder.encodeInt32(self.stateIndex, forKey: "p") 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /TelegramCore/PeerLiveLocationsContext.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func topPeerActiveLiveLocationMessages(viewTracker: AccountViewTracker, accountPeerId: PeerId, peerId: PeerId) -> Signal<(Peer?, [Message]), NoError> { 11 | return viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 50, fixedCombinedReadStates: nil, tagMask: .liveLocation, orderStatistics: [], additionalData: [.peer(accountPeerId)]) 12 | |> map { (view, _, _) -> (Peer?, [Message]) in 13 | var accountPeer: Peer? 14 | for entry in view.additionalData { 15 | if case let .peer(id, peer) = entry { 16 | accountPeer = peer 17 | break 18 | } 19 | } 20 | 21 | let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) 22 | var result: [Message] = [] 23 | for entry in view.entries { 24 | for media in entry.message.media { 25 | if let location = media as? TelegramMediaMap, let liveBroadcastingTimeout = location.liveBroadcastingTimeout { 26 | if entry.message.timestamp + liveBroadcastingTimeout > timestamp { 27 | result.append(entry.message) 28 | } 29 | } else { 30 | assertionFailure() 31 | } 32 | } 33 | } 34 | return (accountPeer, result) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TelegramCore/PeerParticipants.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private struct PeerParticipants: Equatable { 11 | let peers: [Peer] 12 | 13 | static func ==(lhs: PeerParticipants, rhs: PeerParticipants) -> Bool { 14 | if lhs.peers.count != rhs.peers.count { 15 | return false 16 | } 17 | for i in 0 ..< lhs.peers.count { 18 | if !lhs.peers[i].isEqual(rhs.peers[i]) { 19 | return false 20 | } 21 | } 22 | return true 23 | } 24 | } 25 | 26 | public func peerParticipants(postbox: Postbox, id: PeerId) -> Signal<[Peer], NoError> { 27 | return postbox.peerView(id: id) |> map { view -> PeerParticipants in 28 | if let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { 29 | var peers: [Peer] = [] 30 | for participant in participants.participants { 31 | if let peer = view.peers[participant.peerId] { 32 | peers.append(peer) 33 | } 34 | } 35 | return PeerParticipants(peers: peers) 36 | } else { 37 | return PeerParticipants(peers: []) 38 | } 39 | } 40 | |> distinctUntilChanged |> map { participants in 41 | return participants.peers 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TelegramCore/PeerReportStatus.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum PeerReportStatus: Int32 { 4 | case unknown 5 | case none 6 | case canReport 7 | case didReport 8 | } 9 | -------------------------------------------------------------------------------- /TelegramCore/PeerSpecificStickerPack.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private struct WrappedStickerPackCollectionInfo: Equatable { 11 | let info: StickerPackCollectionInfo? 12 | 13 | static func ==(lhs: WrappedStickerPackCollectionInfo, rhs: WrappedStickerPackCollectionInfo) -> Bool { 14 | return lhs.info == rhs.info 15 | } 16 | } 17 | 18 | public struct PeerSpecificStickerPackData { 19 | public let packInfo: (StickerPackCollectionInfo, [ItemCollectionItem])? 20 | public let canSetup: Bool 21 | } 22 | 23 | public func peerSpecificStickerPack(postbox: Postbox, network: Network, peerId: PeerId) -> Signal { 24 | if peerId.namespace == Namespaces.Peer.CloudChannel { 25 | let signal: Signal<(WrappedStickerPackCollectionInfo, Bool), NoError> = postbox.combinedView(keys: [.cachedPeerData(peerId: peerId)]) 26 | |> map { view -> (WrappedStickerPackCollectionInfo, Bool) in 27 | let dataView = view.views[.cachedPeerData(peerId: peerId)] as? CachedPeerDataView 28 | return (WrappedStickerPackCollectionInfo(info: (dataView?.cachedPeerData as? CachedChannelData)?.stickerPack), (dataView?.cachedPeerData as? CachedChannelData)?.flags.contains(.canSetStickerSet) ?? false) 29 | } 30 | |> distinctUntilChanged(isEqual: { lhs, rhs -> Bool in 31 | return lhs.0 == rhs.0 && lhs.1 == rhs.1 32 | }) 33 | 34 | return signal 35 | |> mapToSignal { info, canInstall -> Signal in 36 | if let info = info.info { 37 | return cachedStickerPack(postbox: postbox, network: network, reference: .id(id: info.id.id, accessHash: info.accessHash), forceRemote: false) 38 | |> map { result -> PeerSpecificStickerPackData in 39 | if case let .result(info, items, _) = result { 40 | return PeerSpecificStickerPackData(packInfo: (info, items), canSetup: canInstall) 41 | } else { 42 | return PeerSpecificStickerPackData(packInfo: nil, canSetup: canInstall) 43 | } 44 | } 45 | } else { 46 | return .single(PeerSpecificStickerPackData(packInfo: nil, canSetup: canInstall)) 47 | } 48 | } 49 | } else { 50 | return .single(PeerSpecificStickerPackData(packInfo: nil, canSetup: false)) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TelegramCore/PhoneNumber.swift: -------------------------------------------------------------------------------- 1 | 2 | public struct PhoneNumberWithLabel: Equatable { 3 | public let label: String 4 | public let number: String 5 | 6 | public init(label: String, number: String) { 7 | self.label = label 8 | self.number = number 9 | } 10 | 11 | public static func ==(lhs: PhoneNumberWithLabel, rhs: PhoneNumberWithLabel) -> Bool { 12 | return lhs.label == rhs.label && lhs.number == rhs.number 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TelegramCore/PhoneNumbers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import TelegramCorePrivateModule 3 | 4 | private let phoneNumberUtil = NBPhoneNumberUtil() 5 | 6 | public func formatPhoneNumber(_ string: String) -> String { 7 | do { 8 | let number = try phoneNumberUtil.parse("+" + string, defaultRegion: nil) 9 | return try phoneNumberUtil.format(number, numberFormat: .INTERNATIONAL) 10 | } catch _ { 11 | return string 12 | } 13 | } 14 | 15 | public func isViablePhoneNumber(_ string: String) -> Bool { 16 | return phoneNumberUtil.isViablePhoneNumber(string) 17 | } 18 | -------------------------------------------------------------------------------- /TelegramCore/Random.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func arc4random64() -> Int64 { 4 | var value: Int64 = 0 5 | arc4random_buf(&value, 8) 6 | return value 7 | } 8 | -------------------------------------------------------------------------------- /TelegramCore/RateCall.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import MtProtoKitMac 5 | import SwiftSignalKitMac 6 | #else 7 | import Postbox 8 | import MtProtoKitDynamic 9 | import SwiftSignalKit 10 | #endif 11 | 12 | public func rateCall(account: Account, callId: CallId, starsCount: Int32, comment: String = "", userInitiated: Bool) -> Signal { 13 | var flags: Int32 = 0 14 | if userInitiated { 15 | flags |= (1 << 0) 16 | } 17 | return account.network.request(Api.functions.phone.setCallRating(flags: flags, peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), rating: starsCount, comment: comment)) 18 | |> retryRequest 19 | |> map { _ in } 20 | } 21 | 22 | public func saveCallDebugLog(account: Account, callId: CallId, log: String) -> Signal { 23 | return account.network.request(Api.functions.phone.saveCallDebug(peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), debug: .dataJSON(data: log))) 24 | |> retryRequest 25 | |> map { _ in } 26 | } 27 | -------------------------------------------------------------------------------- /TelegramCore/Reachability.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | Basic demonstration of how to use the SystemConfiguration Reachablity APIs. 7 | */ 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | typedef enum : NSInteger { 15 | NotReachable = 0, 16 | ReachableViaWiFi, 17 | ReachableViaWWAN 18 | } NetworkStatus; 19 | 20 | #pragma mark IPv6 Support 21 | //Reachability fully support IPv6. For full details, see ReadMe.md. 22 | 23 | 24 | extern NSString *kReachabilityChangedNotification; 25 | 26 | 27 | @interface Reachability : NSObject 28 | 29 | @property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status); 30 | 31 | /*! 32 | * Use to check the reachability of a given host name. 33 | */ 34 | + (instancetype)reachabilityWithHostName:(NSString *)hostName; 35 | 36 | /*! 37 | * Use to check the reachability of a given IP address. 38 | */ 39 | + (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress; 40 | 41 | /*! 42 | * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. 43 | */ 44 | + (instancetype)reachabilityForInternetConnection; 45 | 46 | 47 | #pragma mark reachabilityForLocalWiFi 48 | //reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. 49 | //+ (instancetype)reachabilityForLocalWiFi; 50 | 51 | /*! 52 | * Start listening for reachability notifications on the current run loop. 53 | */ 54 | - (BOOL)startNotifier; 55 | - (void)stopNotifier; 56 | 57 | - (NetworkStatus)currentReachabilityStatus; 58 | 59 | /*! 60 | * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. 61 | */ 62 | - (BOOL)connectionRequired; 63 | 64 | @end 65 | 66 | 67 | -------------------------------------------------------------------------------- /TelegramCore/RecentAccountSessions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func requestRecentAccountSessions(account: Account) -> Signal<[RecentAccountSession], NoError> { 11 | return account.network.request(Api.functions.account.getAuthorizations()) 12 | |> retryRequest 13 | |> map { result -> [RecentAccountSession] in 14 | var sessions: [RecentAccountSession] = [] 15 | switch result { 16 | case let .authorizations(authorizations): 17 | for authorization in authorizations { 18 | sessions.append(RecentAccountSession(apiAuthorization: authorization)) 19 | } 20 | } 21 | return sessions 22 | } 23 | } 24 | 25 | public enum TerminateSessionError { 26 | case generic 27 | case freshReset 28 | } 29 | 30 | public func terminateAccountSession(account: Account, hash: Int64) -> Signal { 31 | return account.network.request(Api.functions.account.resetAuthorization(hash: hash)) 32 | |> mapError { error -> TerminateSessionError in 33 | if error.errorCode == 406 { 34 | return .freshReset 35 | } 36 | return .generic 37 | } 38 | |> mapToSignal { _ -> Signal in 39 | return .single(Void()) 40 | } 41 | } 42 | 43 | public func terminateOtherAccountSessions(account: Account) -> Signal { 44 | return account.network.request(Api.functions.auth.resetAuthorizations()) 45 | |> retryRequest 46 | |> mapToSignal { _ -> Signal in 47 | return .single(Void()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /TelegramCore/RecentMediaItem.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct RecentMediaItemId { 9 | public let rawValue: MemoryBuffer 10 | public let mediaId: MediaId 11 | 12 | init(_ rawValue: MemoryBuffer) { 13 | self.rawValue = rawValue 14 | assert(rawValue.length == 4 + 8) 15 | var mediaIdNamespace: Int32 = 0 16 | var mediaIdId: Int64 = 0 17 | memcpy(&mediaIdNamespace, rawValue.memory, 4) 18 | memcpy(&mediaIdId, rawValue.memory.advanced(by: 4), 8) 19 | self.mediaId = MediaId(namespace: mediaIdNamespace, id: mediaIdId) 20 | } 21 | 22 | public init(_ mediaId: MediaId) { 23 | self.mediaId = mediaId 24 | var mediaIdNamespace: Int32 = mediaId.namespace 25 | var mediaIdId: Int64 = mediaId.id 26 | self.rawValue = MemoryBuffer(memory: malloc(4 + 8)!, capacity: 4 + 8, length: 4 + 8, freeWhenDone: true) 27 | memcpy(self.rawValue.memory, &mediaIdNamespace, 4) 28 | memcpy(self.rawValue.memory.advanced(by: 4), &mediaIdId, 8) 29 | } 30 | } 31 | 32 | public final class RecentMediaItem: OrderedItemListEntryContents, Equatable { 33 | public let media: Media 34 | 35 | init(_ media: Media) { 36 | self.media = media 37 | } 38 | 39 | public init(decoder: PostboxDecoder) { 40 | self.media = decoder.decodeObjectForKey("m") as! Media 41 | } 42 | 43 | public func encode(_ encoder: PostboxEncoder) { 44 | encoder.encodeObject(self.media, forKey: "m") 45 | } 46 | 47 | public static func ==(lhs: RecentMediaItem, rhs: RecentMediaItem) -> Bool { 48 | return lhs.media.isEqual(to: rhs.media) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TelegramCore/RecentPeerItem.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct RecentPeerItemId { 9 | public let rawValue: MemoryBuffer 10 | public let peerId: PeerId 11 | 12 | init(_ rawValue: MemoryBuffer) { 13 | self.rawValue = rawValue 14 | assert(rawValue.length == 8) 15 | var idValue: Int64 = 0 16 | memcpy(&idValue, rawValue.memory, 8) 17 | self.peerId = PeerId(idValue) 18 | } 19 | 20 | init(_ peerId: PeerId) { 21 | self.peerId = peerId 22 | var idValue: Int64 = peerId.toInt64() 23 | self.rawValue = MemoryBuffer(memory: malloc(8)!, capacity: 8, length: 8, freeWhenDone: true) 24 | memcpy(self.rawValue.memory, &idValue, 8) 25 | } 26 | } 27 | 28 | public final class RecentPeerItem: OrderedItemListEntryContents { 29 | public let rating: Double 30 | 31 | init(rating: Double) { 32 | self.rating = rating 33 | } 34 | 35 | public init(decoder: PostboxDecoder) { 36 | self.rating = decoder.decodeDoubleForKey("r", orElse: 0.0) 37 | } 38 | 39 | public func encode(_ encoder: PostboxEncoder) { 40 | encoder.encodeDouble(self.rating, forKey: "r") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TelegramCore/RecentlyUsedHashtags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | private struct RecentHashtagItemId { 11 | public let rawValue: MemoryBuffer 12 | 13 | var value: String { 14 | return String(data: self.rawValue.makeData(), encoding: .utf8) ?? "" 15 | } 16 | 17 | init(_ rawValue: MemoryBuffer) { 18 | self.rawValue = rawValue 19 | } 20 | 21 | init?(_ value: String) { 22 | if let data = value.data(using: .utf8) { 23 | self.rawValue = MemoryBuffer(data: data) 24 | } else { 25 | return nil 26 | } 27 | } 28 | } 29 | 30 | final class RecentHashtagItem: OrderedItemListEntryContents { 31 | init() { 32 | } 33 | 34 | public init(decoder: PostboxDecoder) { 35 | } 36 | 37 | public func encode(_ encoder: PostboxEncoder) { 38 | } 39 | } 40 | 41 | func addRecentlyUsedHashtag(transaction: Transaction, string: String) { 42 | if let itemId = RecentHashtagItemId(string) { 43 | transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentHashtagItem()), removeTailIfCountExceeds: 100) 44 | } 45 | } 46 | 47 | public func removeRecentlyUsedHashtag(postbox: Postbox, string: String) -> Signal { 48 | return postbox.transaction { transaction -> Void in 49 | if let itemId = RecentHashtagItemId(string) { 50 | transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, itemId: itemId.rawValue) 51 | } 52 | } 53 | } 54 | 55 | public func recentlyUsedHashtags(postbox: Postbox) -> Signal<[String], NoError> { 56 | return postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.RecentlyUsedHashtags)]) 57 | |> mapToSignal { view -> Signal<[String], NoError> in 58 | return postbox.transaction { transaction -> [String] in 59 | var result: [String] = [] 60 | if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.RecentlyUsedHashtags)] as? OrderedItemListView { 61 | for item in view.items { 62 | let value = RecentHashtagItemId(item.id).value 63 | result.append(value) 64 | } 65 | } 66 | return result 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /TelegramCore/Regex.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Regex { 4 | let pattern: String 5 | let options: NSRegularExpression.Options! 6 | 7 | private var matcher: NSRegularExpression { 8 | return try! NSRegularExpression(pattern: self.pattern, options: self.options) 9 | } 10 | 11 | public init(_ pattern: String) { 12 | self.pattern = pattern 13 | self.options = [] 14 | } 15 | 16 | public func match(_ string: String, options: NSRegularExpression.MatchingOptions = []) -> Bool { 17 | return self.matcher.numberOfMatches(in: string, options: options, range: NSMakeRange(0, string.utf16.count)) != 0 18 | } 19 | } 20 | 21 | public protocol RegularExpressionMatchable { 22 | func match(_ regex: Regex) -> Bool 23 | } 24 | 25 | extension String: RegularExpressionMatchable { 26 | public func match(_ regex: Regex) -> Bool { 27 | return regex.match(self) 28 | } 29 | } 30 | 31 | public func ~=(pattern: Regex, matchable: T) -> Bool { 32 | return matchable.match(pattern) 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/RegisterNotificationToken.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import SwiftSignalKitMac 4 | import PostboxMac 5 | #else 6 | import SwiftSignalKit 7 | import Postbox 8 | #endif 9 | 10 | public enum NotificationTokenType { 11 | case aps(encrypt: Bool) 12 | case voip 13 | } 14 | 15 | public func unregisterNotificationToken(account: Account, token: Data, type: NotificationTokenType, otherAccountUserIds: [Int32]) -> Signal { 16 | let mappedType: Int32 17 | switch type { 18 | case .aps: 19 | mappedType = 1 20 | case .voip: 21 | mappedType = 9 22 | } 23 | return account.network.request(Api.functions.account.unregisterDevice(tokenType: mappedType, token: hexString(token), otherUids: otherAccountUserIds)) 24 | |> retryRequest 25 | |> ignoreValues 26 | } 27 | 28 | public func registerNotificationToken(account: Account, token: Data, type: NotificationTokenType, sandbox: Bool, otherAccountUserIds: [Int32]) -> Signal { 29 | return masterNotificationsKey(account: account, ignoreDisabled: false) 30 | |> mapToSignal { masterKey -> Signal in 31 | let mappedType: Int32 32 | var keyData = Data() 33 | switch type { 34 | case let .aps(encrypt): 35 | mappedType = 1 36 | if encrypt { 37 | keyData = masterKey.data 38 | } 39 | case .voip: 40 | mappedType = 9 41 | keyData = masterKey.data 42 | } 43 | return account.network.request(Api.functions.account.registerDevice(tokenType: mappedType, token: hexString(token), appSandbox: sandbox ? .boolTrue : .boolFalse, secret: Buffer(data: keyData), otherUids: otherAccountUserIds)) 44 | |> retryRequest 45 | |> ignoreValues 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /TelegramCore/RegularChatState.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | final class RegularChatState: PeerChatState, Equatable { 9 | let invalidatedPts: Int32? 10 | 11 | init(invalidatedPts: Int32?) { 12 | self.invalidatedPts = invalidatedPts 13 | } 14 | 15 | init(decoder: PostboxDecoder) { 16 | self.invalidatedPts = decoder.decodeOptionalInt32ForKey("ipts") 17 | } 18 | 19 | func encode(_ encoder: PostboxEncoder) { 20 | if let invalidatedPts = self.invalidatedPts { 21 | encoder.encodeInt32(invalidatedPts, forKey: "ipts") 22 | } else { 23 | encoder.encodeNil(forKey: "ipts") 24 | } 25 | } 26 | 27 | func withUpdatedInvalidatedPts(_ invalidatedPts: Int32?) -> RegularChatState { 28 | return RegularChatState(invalidatedPts: invalidatedPts) 29 | } 30 | 31 | func equals(_ other: PeerChatState) -> Bool { 32 | if let other = other as? RegularChatState, other == self { 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | static func ==(lhs: RegularChatState, rhs: RegularChatState) -> Bool { 39 | return lhs.invalidatedPts == rhs.invalidatedPts 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TelegramCore/RemoteStorageConfiguration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public final class RemoteStorageConfiguration: PreferencesEntry { 11 | public let webDocumentsHostDatacenterId: Int32 12 | 13 | init(webDocumentsHostDatacenterId: Int32) { 14 | self.webDocumentsHostDatacenterId = webDocumentsHostDatacenterId 15 | } 16 | 17 | public init(decoder: PostboxDecoder) { 18 | self.webDocumentsHostDatacenterId = decoder.decodeInt32ForKey("webDocumentsHostDatacenterId", orElse: 4) 19 | } 20 | 21 | public func encode(_ encoder: PostboxEncoder) { 22 | encoder.encodeInt32(self.webDocumentsHostDatacenterId, forKey: "webDocumentsHostDatacenterId") 23 | } 24 | 25 | public func isEqual(to: PreferencesEntry) -> Bool { 26 | guard let to = to as? RemoteStorageConfiguration else { 27 | return false 28 | } 29 | if self.webDocumentsHostDatacenterId != to.webDocumentsHostDatacenterId { 30 | return false 31 | } 32 | return true 33 | } 34 | } 35 | 36 | public func currentWebDocumentsHostDatacenterId(postbox: Postbox, isTestingEnvironment: Bool) -> Signal { 37 | return postbox.transaction { transaction -> Int32 in 38 | if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration) as? RemoteStorageConfiguration { 39 | return entry.webDocumentsHostDatacenterId 40 | } else { 41 | if isTestingEnvironment { 42 | return 2 43 | } else { 44 | return 4 45 | } 46 | } 47 | } 48 | } 49 | 50 | func updateRemoteStorageConfiguration(transaction: Transaction, configuration: RemoteStorageConfiguration) { 51 | let current = transaction.getPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration) as? RemoteStorageConfiguration 52 | if let current = current, current.isEqual(to: configuration) { 53 | return 54 | } 55 | 56 | transaction.setPreferencesEntry(key: PreferencesKeys.remoteStorageConfiguration, value: configuration) 57 | } 58 | -------------------------------------------------------------------------------- /TelegramCore/ReplyMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ReplyMessageAttribute: MessageAttribute { 9 | public let messageId: MessageId 10 | 11 | public var associatedMessageIds: [MessageId] { 12 | return [self.messageId] 13 | } 14 | 15 | public init(messageId: MessageId) { 16 | self.messageId = messageId 17 | } 18 | 19 | required public init(decoder: PostboxDecoder) { 20 | let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i", orElse: 0) 21 | self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) 22 | } 23 | 24 | public func encode(_ encoder: PostboxEncoder) { 25 | let namespaceAndId = Int64(self.messageId.namespace) | (Int64(self.messageId.id) << 32) 26 | encoder.encodeInt64(namespaceAndId, forKey: "i") 27 | encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TelegramCore/RequestChatContextResults.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public func requestChatContextResults(account: Account, botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String) -> Signal { 13 | return combineLatest(account.postbox.transaction { transaction -> (bot: Peer, peer: Peer)? in 14 | if let bot = transaction.getPeer(botId), let peer = transaction.getPeer(peerId) { 15 | return (bot, peer) 16 | } else { 17 | return nil 18 | } 19 | }, location) 20 | |> mapToSignal { botAndPeer, location -> Signal in 21 | if let (bot, peer) = botAndPeer, let inputBot = apiInputUser(bot) { 22 | var flags: Int32 = 0 23 | var inputPeer: Api.InputPeer = .inputPeerEmpty 24 | var geoPoint: Api.InputGeoPoint? 25 | if let actualInputPeer = apiInputPeer(peer) { 26 | inputPeer = actualInputPeer 27 | } 28 | if let (latitude, longitude) = location { 29 | flags |= (1 << 0) 30 | geoPoint = Api.InputGeoPoint.inputGeoPoint(lat: latitude, long: longitude) 31 | } 32 | return account.network.request(Api.functions.messages.getInlineBotResults(flags: flags, bot: inputBot, peer: inputPeer, geoPoint: geoPoint, query: query, offset: offset)) 33 | |> map { result -> ChatContextResultCollection? in 34 | return ChatContextResultCollection(apiResults: result, botId: bot.id, peerId: peerId, query: query, geoPoint: location) 35 | } 36 | |> `catch` { _ -> Signal in 37 | return .single(nil) 38 | } 39 | } else { 40 | return .single(nil) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TelegramCore/RequestPhoneNumber.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func requestPhoneNumber(account: Account, peerId: PeerId) -> Signal { 11 | return .never() 12 | /*return account.postbox.transaction { transaction -> Api.InputPeer? in 13 | return transaction.getPeer(peerId).flatMap(apiInputPeer) 14 | } 15 | |> mapToSignal { inputPeer -> Signal in 16 | guard let inputPeer = inputPeer else { 17 | return .complete() 18 | } 19 | return account.network.request(Api.functions.messages.sendPhoneNumberRequest(peer: inputPeer, randomId: arc4random64())) 20 | |> map(Optional.init) 21 | |> `catch` { _ -> Signal in 22 | return .single(nil) 23 | } 24 | |> mapToSignal { updates -> Signal in 25 | if let updates = updates { 26 | account.stateManager.addUpdates(updates) 27 | } 28 | return .complete() 29 | } 30 | }*/ 31 | } 32 | 33 | -------------------------------------------------------------------------------- /TelegramCore/SavedStickerItem.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class SavedStickerItem: OrderedItemListEntryContents, Equatable { 9 | public let file: TelegramMediaFile 10 | public let stringRepresentations: [String] 11 | 12 | init(file: TelegramMediaFile, stringRepresentations: [String]) { 13 | self.file = file 14 | self.stringRepresentations = stringRepresentations 15 | } 16 | 17 | public init(decoder: PostboxDecoder) { 18 | self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile 19 | self.stringRepresentations = decoder.decodeStringArrayForKey("sr") 20 | } 21 | 22 | public func encode(_ encoder: PostboxEncoder) { 23 | encoder.encodeObject(self.file, forKey: "f") 24 | encoder.encodeStringArray(self.stringRepresentations, forKey: "sr") 25 | } 26 | 27 | public static func ==(lhs: SavedStickerItem, rhs: SavedStickerItem) -> Bool { 28 | return lhs.file.isEqual(to: rhs.file) && lhs.stringRepresentations == rhs.stringRepresentations 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TelegramCore/SearchBotsConfiguration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public struct SearchBotsConfiguration: Equatable, PreferencesEntry { 9 | public let imageBotUsername: String? 10 | public let gifBotUsername: String? 11 | public let venueBotUsername: String? 12 | 13 | public static var defaultValue: SearchBotsConfiguration { 14 | return SearchBotsConfiguration(imageBotUsername: "bing", gifBotUsername: "gif", venueBotUsername: "foursquare") 15 | } 16 | 17 | init(imageBotUsername: String?, gifBotUsername: String?, venueBotUsername: String?) { 18 | self.imageBotUsername = imageBotUsername 19 | self.gifBotUsername = gifBotUsername 20 | self.venueBotUsername = venueBotUsername 21 | } 22 | 23 | public init(decoder: PostboxDecoder) { 24 | self.imageBotUsername = decoder.decodeOptionalStringForKey("img") 25 | self.gifBotUsername = decoder.decodeOptionalStringForKey("gif") 26 | self.venueBotUsername = decoder.decodeOptionalStringForKey("venue") 27 | } 28 | 29 | public func encode(_ encoder: PostboxEncoder) { 30 | if let imageBotUsername = self.imageBotUsername { 31 | encoder.encodeString(imageBotUsername, forKey: "img") 32 | } else { 33 | encoder.encodeNil(forKey: "img") 34 | } 35 | if let gifBotUsername = self.gifBotUsername { 36 | encoder.encodeString(gifBotUsername, forKey: "gif") 37 | } else { 38 | encoder.encodeNil(forKey: "gif") 39 | } 40 | if let venueBotUsername = self.venueBotUsername { 41 | encoder.encodeString(venueBotUsername, forKey: "venue") 42 | } else { 43 | encoder.encodeNil(forKey: "venue") 44 | } 45 | } 46 | 47 | public func isEqual(to: PreferencesEntry) -> Bool { 48 | guard let to = to as? SearchBotsConfiguration else { 49 | return false 50 | } 51 | return self == to 52 | } 53 | } 54 | 55 | public func currentSearchBotsConfiguration(transaction: Transaction) -> SearchBotsConfiguration { 56 | if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration) as? SearchBotsConfiguration { 57 | return entry 58 | } else { 59 | return SearchBotsConfiguration.defaultValue 60 | } 61 | } 62 | 63 | func updateSearchBotsConfiguration(transaction: Transaction, configuration: SearchBotsConfiguration) { 64 | if !currentSearchBotsConfiguration(transaction: transaction).isEqual(to: configuration) { 65 | transaction.setPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration, value: configuration) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /TelegramCore/SecretChatEncryptionConfig.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public final class SecretChatEncryptionConfig: PostboxCoding { 13 | let g: Int32 14 | let p: MemoryBuffer 15 | let version: Int32 16 | 17 | public init(g: Int32, p: MemoryBuffer, version: Int32) { 18 | self.g = g 19 | self.p = p 20 | self.version = version 21 | } 22 | 23 | public init(decoder: PostboxDecoder) { 24 | self.g = decoder.decodeInt32ForKey("g", orElse: 0) 25 | self.p = decoder.decodeBytesForKey("p")! 26 | self.version = decoder.decodeInt32ForKey("v", orElse: 0) 27 | } 28 | 29 | public func encode(_ encoder: PostboxEncoder) { 30 | encoder.encodeInt32(self.g, forKey: "g") 31 | encoder.encodeBytes(self.p, forKey: "p") 32 | encoder.encodeInt32(self.version, forKey: "v") 33 | } 34 | } 35 | 36 | func validatedEncryptionConfig(postbox: Postbox, network: Network) -> Signal { 37 | return network.request(Api.functions.messages.getDhConfig(version: 0, randomLength: 0)) 38 | |> retryRequest 39 | |> mapToSignal { result -> Signal in 40 | switch result { 41 | case let .dhConfig(g, p, version, _): 42 | if !MTCheckIsSafeG(UInt32(g)) { 43 | Logger.shared.log("SecretChatEncryptionConfig", "Invalid g") 44 | return .complete() 45 | } 46 | 47 | if !MTCheckMod(p.makeData(), UInt32(g), network.context.keychain) { 48 | Logger.shared.log("SecretChatEncryptionConfig", "Invalid p or g") 49 | return .complete() 50 | } 51 | 52 | if !MTCheckIsSafePrime(p.makeData(), network.context.keychain) { 53 | Logger.shared.log("SecretChatEncryptionConfig", "Invalid p") 54 | return .never() 55 | } 56 | return .single(SecretChatEncryptionConfig(g: g, p: MemoryBuffer(p), version: version)) 57 | case .dhConfigNotModified(_): 58 | assertionFailure() 59 | return .never() 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /TelegramCore/SecretChatFileReference.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | final class SecretChatFileReference: PostboxCoding { 9 | let id: Int64 10 | let accessHash: Int64 11 | let size: Int32 12 | let datacenterId: Int32 13 | let keyFingerprint: Int32 14 | 15 | init(id: Int64, accessHash: Int64, size: Int32, datacenterId: Int32, keyFingerprint: Int32) { 16 | self.id = id 17 | self.accessHash = accessHash 18 | self.size = size 19 | self.datacenterId = datacenterId 20 | self.keyFingerprint = keyFingerprint 21 | } 22 | 23 | init(decoder: PostboxDecoder) { 24 | self.id = decoder.decodeInt64ForKey("i", orElse: 0) 25 | self.accessHash = decoder.decodeInt64ForKey("a", orElse: 0) 26 | self.size = decoder.decodeInt32ForKey("s", orElse: 0) 27 | self.datacenterId = decoder.decodeInt32ForKey("d", orElse: 0) 28 | self.keyFingerprint = decoder.decodeInt32ForKey("f", orElse: 0) 29 | } 30 | 31 | func encode(_ encoder: PostboxEncoder) { 32 | encoder.encodeInt64(self.id, forKey: "i") 33 | encoder.encodeInt64(self.accessHash, forKey: "a") 34 | encoder.encodeInt32(self.size, forKey: "s") 35 | encoder.encodeInt32(self.datacenterId, forKey: "d") 36 | encoder.encodeInt32(self.keyFingerprint, forKey: "f") 37 | } 38 | } 39 | 40 | extension SecretChatFileReference { 41 | convenience init?(_ file: Api.EncryptedFile) { 42 | switch file { 43 | case let .encryptedFile(id, accessHash, size, dcId, keyFingerprint): 44 | self.init(id: id, accessHash: accessHash, size: size, datacenterId: dcId, keyFingerprint: keyFingerprint) 45 | case .encryptedFileEmpty: 46 | return nil 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /TelegramCore/SecretChatIncomingDecryptedOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | struct SecretChatOperationSequenceInfo: PostboxCoding { 9 | let topReceivedOperationIndex: Int32 10 | let operationIndex: Int32 11 | 12 | init(topReceivedOperationIndex: Int32, operationIndex: Int32) { 13 | self.topReceivedOperationIndex = topReceivedOperationIndex 14 | self.operationIndex = operationIndex 15 | } 16 | 17 | init(decoder: PostboxDecoder) { 18 | self.topReceivedOperationIndex = decoder.decodeInt32ForKey("r", orElse: 0) 19 | self.operationIndex = decoder.decodeInt32ForKey("o", orElse: 0) 20 | } 21 | 22 | func encode(_ encoder: PostboxEncoder) { 23 | encoder.encodeInt32(self.topReceivedOperationIndex, forKey: "r") 24 | encoder.encodeInt32(self.operationIndex, forKey: "o") 25 | } 26 | } 27 | 28 | final class SecretChatIncomingDecryptedOperation: PostboxCoding { 29 | let timestamp: Int32 30 | let layer: Int32 31 | let sequenceInfo: SecretChatOperationSequenceInfo? 32 | let contents: MemoryBuffer 33 | let file: SecretChatFileReference? 34 | 35 | init(timestamp: Int32, layer: Int32, sequenceInfo: SecretChatOperationSequenceInfo?, contents: MemoryBuffer, file: SecretChatFileReference?) { 36 | self.timestamp = timestamp 37 | self.layer = layer 38 | self.sequenceInfo = sequenceInfo 39 | self.contents = contents 40 | self.file = file 41 | } 42 | 43 | init(decoder: PostboxDecoder) { 44 | self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) 45 | self.layer = decoder.decodeInt32ForKey("l", orElse: 0) 46 | self.sequenceInfo = decoder.decodeObjectForKey("s", decoder: { SecretChatOperationSequenceInfo(decoder: $0) }) as? SecretChatOperationSequenceInfo 47 | self.contents = decoder.decodeBytesForKey("c")! 48 | self.file = decoder.decodeObjectForKey("f", decoder: { SecretChatFileReference(decoder: $0) }) as? SecretChatFileReference 49 | } 50 | 51 | func encode(_ encoder: PostboxEncoder) { 52 | encoder.encodeInt32(self.timestamp, forKey: "t") 53 | encoder.encodeInt32(self.layer, forKey: "l") 54 | if let sequenceInfo = self.sequenceInfo { 55 | encoder.encodeObject(sequenceInfo, forKey: "s") 56 | } else { 57 | encoder.encodeNil(forKey: "s") 58 | } 59 | encoder.encodeBytes(self.contents, forKey: "c") 60 | if let file = self.file { 61 | encoder.encodeObject(file, forKey: "f") 62 | } else { 63 | encoder.encodeNil(forKey: "f") 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdAddressValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdAddressValue: Equatable { 4 | public var street1: String 5 | public var street2: String 6 | public var city: String 7 | public var state: String 8 | public var countryCode: String 9 | public var postcode: String 10 | 11 | public init(street1: String, street2: String, city: String, state: String, countryCode: String, postcode: String) { 12 | self.street1 = street1 13 | self.street2 = street2 14 | self.city = city 15 | self.state = state 16 | self.countryCode = countryCode 17 | self.postcode = postcode 18 | } 19 | 20 | public static func ==(lhs: SecureIdAddressValue, rhs: SecureIdAddressValue) -> Bool { 21 | if lhs.street1 != rhs.street1 { 22 | return false 23 | } 24 | if lhs.street2 != rhs.street2 { 25 | return false 26 | } 27 | if lhs.city != rhs.city { 28 | return false 29 | } 30 | if lhs.state != rhs.state { 31 | return false 32 | } 33 | if lhs.countryCode != rhs.countryCode { 34 | return false 35 | } 36 | if lhs.postcode != rhs.postcode { 37 | return false 38 | } 39 | return true 40 | } 41 | } 42 | 43 | extension SecureIdAddressValue { 44 | init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference]) { 45 | guard let street1 = dict["street_line1"] as? String else { 46 | return nil 47 | } 48 | let street2 = (dict["street_line2"] as? String) ?? "" 49 | guard let city = dict["city"] as? String else { 50 | return nil 51 | } 52 | guard let state = dict["state"] as? String else { 53 | return nil 54 | } 55 | guard let countryCode = dict["country_code"] as? String else { 56 | return nil 57 | } 58 | guard let postcode = dict["post_code"] as? String else { 59 | return nil 60 | } 61 | 62 | self.init(street1: street1, street2: street2, city: city, state: state, countryCode: countryCode, postcode: postcode) 63 | } 64 | 65 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference]) { 66 | var dict: [String: Any] = [:] 67 | dict["street_line1"] = self.street1 68 | if !self.street2.isEmpty { 69 | dict["street_line2"] = self.street2 70 | } 71 | dict["city"] = self.city 72 | dict["state"] = self.state 73 | dict["country_code"] = self.countryCode 74 | dict["post_code"] = self.postcode 75 | 76 | return (dict, []) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdBankStatementValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdBankStatementValue: Equatable { 4 | public var verificationDocuments: [SecureIdVerificationDocumentReference] 5 | public var translations: [SecureIdVerificationDocumentReference] 6 | 7 | public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 8 | self.verificationDocuments = verificationDocuments 9 | self.translations = translations 10 | } 11 | 12 | public static func ==(lhs: SecureIdBankStatementValue, rhs: SecureIdBankStatementValue) -> Bool { 13 | if lhs.verificationDocuments != rhs.verificationDocuments { 14 | return false 15 | } 16 | if lhs.translations != rhs.translations { 17 | return false 18 | } 19 | return true 20 | } 21 | } 22 | 23 | extension SecureIdBankStatementValue { 24 | init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 25 | let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences 26 | 27 | self.init(verificationDocuments: verificationDocuments, translations: translations) 28 | } 29 | 30 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { 31 | return ([:], self.verificationDocuments, self.translations) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdEmailValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdEmailValue: Equatable { 4 | public let email: String 5 | 6 | public init(email: String) { 7 | self.email = email 8 | } 9 | 10 | public static func ==(lhs: SecureIdEmailValue, rhs: SecureIdEmailValue) -> Bool { 11 | if lhs.email != rhs.email { 12 | return false 13 | } 14 | return true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdForm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public enum SecureIdRequestedFormField: Equatable { 9 | case just(SecureIdRequestedFormFieldValue) 10 | case oneOf([SecureIdRequestedFormFieldValue]) 11 | } 12 | 13 | public enum SecureIdRequestedFormFieldValue: Equatable { 14 | case personalDetails(nativeName: Bool) 15 | case passport(selfie: Bool, translation: Bool) 16 | case driversLicense(selfie: Bool, translation: Bool) 17 | case idCard(selfie: Bool, translation: Bool) 18 | case internalPassport(selfie: Bool, translation: Bool) 19 | case passportRegistration(translation: Bool) 20 | case address 21 | case utilityBill(translation: Bool) 22 | case bankStatement(translation: Bool) 23 | case rentalAgreement(translation: Bool) 24 | case phone 25 | case email 26 | case temporaryRegistration(translation: Bool) 27 | } 28 | 29 | public struct SecureIdForm: Equatable { 30 | public let peerId: PeerId 31 | public let requestedFields: [SecureIdRequestedFormField] 32 | public let values: [SecureIdValueWithContext] 33 | 34 | public init(peerId: PeerId, requestedFields: [SecureIdRequestedFormField], values: [SecureIdValueWithContext]) { 35 | self.peerId = peerId 36 | self.requestedFields = requestedFields 37 | self.values = values 38 | } 39 | 40 | public static func ==(lhs: SecureIdForm, rhs: SecureIdForm) -> Bool { 41 | if lhs.peerId != rhs.peerId { 42 | return false 43 | } 44 | if lhs.requestedFields != rhs.requestedFields { 45 | return false 46 | } 47 | if lhs.values != rhs.values { 48 | return false 49 | } 50 | return true 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdPadding.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func paddedSecureIdData(_ data: Data) -> Data { 4 | var paddingCount = Int(47 + arc4random_uniform(255 - 47)) 5 | paddingCount -= ((data.count + paddingCount) % 16) 6 | var result = Data(count: paddingCount + data.count) 7 | result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in 8 | bytes.advanced(by: 0).pointee = UInt8(paddingCount) 9 | arc4random_buf(bytes.advanced(by: 1), paddingCount - 1) 10 | data.withUnsafeBytes { (source: UnsafePointer) -> Void in 11 | memcpy(bytes.advanced(by: paddingCount), source, data.count) 12 | } 13 | } 14 | return result 15 | } 16 | 17 | func unpaddedSecureIdData(_ data: Data) -> Data? { 18 | var paddingCount: UInt8 = 0 19 | data.copyBytes(to: &paddingCount, count: 1) 20 | 21 | if paddingCount < 0 || paddingCount > data.count { 22 | return nil 23 | } 24 | 25 | return data.subdata(in: Int(paddingCount) ..< data.count) 26 | } 27 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdPassportRegistrationValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdPassportRegistrationValue: Equatable { 4 | public var verificationDocuments: [SecureIdVerificationDocumentReference] 5 | public var translations: [SecureIdVerificationDocumentReference] 6 | 7 | public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 8 | self.verificationDocuments = verificationDocuments 9 | self.translations = translations 10 | } 11 | 12 | public static func ==(lhs: SecureIdPassportRegistrationValue, rhs: SecureIdPassportRegistrationValue) -> Bool { 13 | if lhs.verificationDocuments != rhs.verificationDocuments { 14 | return false 15 | } 16 | if lhs.translations != rhs.translations { 17 | return false 18 | } 19 | return true 20 | } 21 | } 22 | 23 | extension SecureIdPassportRegistrationValue { 24 | init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 25 | let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences 26 | 27 | self.init(verificationDocuments: verificationDocuments, translations: translations) 28 | } 29 | 30 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { 31 | return ([:], self.verificationDocuments, self.translations) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdPhoneValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdPhoneValue: Equatable { 4 | public let phone: String 5 | 6 | public init(phone: String) { 7 | self.phone = phone 8 | } 9 | 10 | public static func ==(lhs: SecureIdPhoneValue, rhs: SecureIdPhoneValue) -> Bool { 11 | if lhs.phone != rhs.phone { 12 | return false 13 | } 14 | return true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdRentalAgreementValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdRentalAgreementValue: Equatable { 4 | public var verificationDocuments: [SecureIdVerificationDocumentReference] 5 | public var translations: [SecureIdVerificationDocumentReference] 6 | 7 | public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 8 | self.verificationDocuments = verificationDocuments 9 | self.translations = translations 10 | } 11 | 12 | public static func ==(lhs: SecureIdRentalAgreementValue, rhs: SecureIdRentalAgreementValue) -> Bool { 13 | if lhs.verificationDocuments != rhs.verificationDocuments { 14 | return false 15 | } 16 | if lhs.translations != rhs.translations { 17 | return false 18 | } 19 | return true 20 | } 21 | } 22 | 23 | extension SecureIdRentalAgreementValue { 24 | init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 25 | let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences 26 | 27 | self.init(verificationDocuments: verificationDocuments, translations: translations) 28 | } 29 | 30 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { 31 | return ([:], self.verificationDocuments, self.translations) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdTemporaryRegistrationValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdTemporaryRegistrationValue: Equatable { 4 | public var verificationDocuments: [SecureIdVerificationDocumentReference] 5 | public var translations: [SecureIdVerificationDocumentReference] 6 | 7 | public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 8 | self.verificationDocuments = verificationDocuments 9 | self.translations = translations 10 | } 11 | 12 | public static func ==(lhs: SecureIdTemporaryRegistrationValue, rhs: SecureIdTemporaryRegistrationValue) -> Bool { 13 | if lhs.verificationDocuments != rhs.verificationDocuments { 14 | return false 15 | } 16 | if lhs.translations != rhs.translations { 17 | return false 18 | } 19 | return true 20 | } 21 | } 22 | 23 | extension SecureIdTemporaryRegistrationValue { 24 | init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 25 | let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences 26 | 27 | self.init(verificationDocuments: verificationDocuments, translations: translations) 28 | } 29 | 30 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { 31 | return ([:], self.verificationDocuments, self.translations) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdUtilityBillValue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdUtilityBillValue: Equatable { 4 | public var verificationDocuments: [SecureIdVerificationDocumentReference] 5 | public var translations: [SecureIdVerificationDocumentReference] 6 | 7 | public init(verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 8 | self.verificationDocuments = verificationDocuments 9 | self.translations = translations 10 | } 11 | 12 | public static func ==(lhs: SecureIdUtilityBillValue, rhs: SecureIdUtilityBillValue) -> Bool { 13 | if lhs.verificationDocuments != rhs.verificationDocuments { 14 | return false 15 | } 16 | if lhs.translations != rhs.translations { 17 | return false 18 | } 19 | return true 20 | } 21 | } 22 | 23 | extension SecureIdUtilityBillValue { 24 | init?(fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference]) { 25 | let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences 26 | 27 | self.init(verificationDocuments: verificationDocuments, translations: translations) 28 | } 29 | 30 | func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference]) { 31 | return ([:], self.verificationDocuments, self.translations) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdValueAccessContext.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SecureIdValueAccessContext: Equatable { 4 | let secret: Data 5 | let id: Int64 6 | 7 | public static func ==(lhs: SecureIdValueAccessContext, rhs: SecureIdValueAccessContext) -> Bool { 8 | if lhs.secret != rhs.secret { 9 | return false 10 | } 11 | if lhs.id != rhs.id { 12 | return false 13 | } 14 | return true 15 | } 16 | } 17 | 18 | public func generateSecureIdValueEmptyAccessContext() -> SecureIdValueAccessContext? { 19 | return SecureIdValueAccessContext(secret: Data(), id: 0) 20 | } 21 | 22 | public func generateSecureIdValueAccessContext() -> SecureIdValueAccessContext? { 23 | guard let secret = generateSecureSecretData() else { 24 | return nil 25 | } 26 | let secretHashData = sha512Digest(secret) 27 | var secretHash: Int64 = 0 28 | secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in 29 | memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) 30 | } 31 | return SecureIdValueAccessContext(secret: secret, id: secretHash) 32 | } 33 | -------------------------------------------------------------------------------- /TelegramCore/SecureIdVerificationDocumentReference.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum SecureIdVerificationDocumentReference: Equatable { 4 | case remote(SecureIdFileReference) 5 | case uploaded(UploadedSecureIdFile) 6 | 7 | public static func ==(lhs: SecureIdVerificationDocumentReference, rhs: SecureIdVerificationDocumentReference) -> Bool { 8 | switch lhs { 9 | case let .remote(file): 10 | if case .remote(file) = rhs { 11 | return true 12 | } else { 13 | return false 14 | } 15 | case let .uploaded(file): 16 | if case .uploaded(file) = rhs { 17 | return true 18 | } else { 19 | return false 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TelegramCore/SetSecretChatMessageAutoremoveTimeoutInteractively.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func setSecretChatMessageAutoremoveTimeoutInteractively(account: Account, peerId: PeerId, timeout: Int32?) -> Signal { 11 | return account.postbox.transaction { transaction -> Void in 12 | if let peer = transaction.getPeer(peerId) as? TelegramSecretChat, let state = transaction.getPeerChatState(peerId) as? SecretChatState { 13 | if state.messageAutoremoveTimeout != timeout { 14 | let updatedPeer = peer.withUpdatedMessageAutoremoveTimeout(timeout) 15 | let updatedState = state.withUpdatedMessageAutoremoveTimeout(timeout) 16 | if !updatedPeer.isEqual(peer) { 17 | updatePeers(transaction: transaction, peers: [updatedPeer], update: { $1 }) 18 | } 19 | if updatedState != state { 20 | transaction.setPeerChatState(peerId, state: updatedState) 21 | } 22 | 23 | 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))]) 24 | } 25 | } 26 | } 27 | } 28 | 29 | public func addSecretChatMessageScreenshot(account: Account, peerId: PeerId) -> Signal { 30 | return account.postbox.transaction { transaction -> Void in 31 | if let peer = transaction.getPeer(peerId) as? TelegramSecretChat, let state = transaction.getPeerChatState(peerId) as? SecretChatState { 32 | let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil))]) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TelegramCore/SourceReferenceMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class SourceReferenceMessageAttribute: MessageAttribute { 9 | public let messageId: MessageId 10 | public let associatedMessageIds: [MessageId] = [] 11 | public let associatedPeerIds: [PeerId] 12 | 13 | public init(messageId: MessageId) { 14 | self.messageId = messageId 15 | self.associatedPeerIds = [messageId.peerId] 16 | } 17 | 18 | required public init(decoder: PostboxDecoder) { 19 | let namespaceAndId: Int64 = decoder.decodeInt64ForKey("i", orElse: 0) 20 | self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("p", orElse: 0)), namespace: Int32(namespaceAndId & 0xffffffff), id: Int32((namespaceAndId >> 32) & 0xffffffff)) 21 | self.associatedPeerIds = [self.messageId.peerId] 22 | } 23 | 24 | public func encode(_ encoder: PostboxEncoder) { 25 | let namespaceAndId = Int64(self.messageId.namespace) | (Int64(self.messageId.id) << 32) 26 | encoder.encodeInt64(namespaceAndId, forKey: "i") 27 | encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "p") 28 | } 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /TelegramCore/SplitTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public protocol SplitTestEvent: RawRepresentable where RawValue == String { 9 | } 10 | 11 | public protocol SplitTestConfiguration { 12 | static var defaultValue: Self { get } 13 | } 14 | 15 | public protocol SplitTest { 16 | associatedtype Configuration: SplitTestConfiguration 17 | associatedtype Event: SplitTestEvent 18 | 19 | var postbox: Postbox { get } 20 | var bucket: String? { get } 21 | var configuration: Configuration { get } 22 | 23 | init(postbox: Postbox, bucket: String?, configuration: Configuration) 24 | } 25 | 26 | extension SplitTest { 27 | public func addEvent(_ event: Self.Event, data: JSON = []) { 28 | if let bucket = self.bucket { 29 | //TODO: merge additional data 30 | addAppLogEvent(postbox: self.postbox, time: Date().timeIntervalSince1970, type: event.rawValue, peerId: nil, data: ["bucket": bucket]) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/StringFormat.swift: -------------------------------------------------------------------------------- 1 | public func dataSizeString(_ size: Int, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { 2 | return dataSizeString(Int64(size), forceDecimal: forceDecimal, decimalSeparator: decimalSeparator) 3 | } 4 | 5 | public func dataSizeString(_ size: Int64, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { 6 | if size >= 1024 * 1024 * 1024 { 7 | let remainder = Int64((Double(size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102.4)).rounded(.down)) 8 | if remainder != 0 || forceDecimal { 9 | return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB" 10 | } else { 11 | return "\(size / (1024 * 1024 * 1024)) GB" 12 | } 13 | } else if size >= 1024 * 1024 { 14 | let remainder = Int64((Double(size % (1024 * 1024)) / (1024.0 * 102.4)).rounded(.down)) 15 | if remainder != 0 || forceDecimal { 16 | return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB" 17 | } else { 18 | return "\(size / (1024 * 1024)) MB" 19 | } 20 | } else if size >= 1024 { 21 | let remainder = (size % (1024)) / (102) 22 | if remainder != 0 || forceDecimal { 23 | return "\(size / 1024)\(decimalSeparator)\(remainder) KB" 24 | } else { 25 | return "\(size / 1024) KB" 26 | } 27 | } else { 28 | return "\(size) B" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TelegramCore/SuggestedLocalizationEntry.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public final class SuggestedLocalizationEntry: PreferencesEntry { 11 | public let languageCode: String 12 | public let isSeen: Bool 13 | 14 | init(languageCode: String, isSeen: Bool) { 15 | self.languageCode = languageCode 16 | self.isSeen = isSeen 17 | } 18 | 19 | public init(decoder: PostboxDecoder) { 20 | self.languageCode = decoder.decodeStringForKey("lc", orElse: "en") 21 | self.isSeen = decoder.decodeInt32ForKey("s", orElse: 0) != 0 22 | } 23 | 24 | public func encode(_ encoder: PostboxEncoder) { 25 | encoder.encodeString(self.languageCode, forKey: "lc") 26 | encoder.encodeInt32(self.isSeen ? 1 : 0, forKey: "s") 27 | } 28 | 29 | public func isEqual(to: PreferencesEntry) -> Bool { 30 | if let to = to as? SuggestedLocalizationEntry { 31 | return self == to 32 | } else { 33 | return false 34 | } 35 | } 36 | 37 | public static func ==(lhs: SuggestedLocalizationEntry, rhs: SuggestedLocalizationEntry) -> Bool { 38 | return lhs.languageCode == rhs.languageCode && lhs.isSeen == rhs.isSeen 39 | } 40 | } 41 | 42 | public func markSuggestedLocalizationAsSeenInteractively(postbox: Postbox, languageCode: String) -> Signal { 43 | return postbox.transaction { transaction -> Void in 44 | transaction.updatePreferencesEntry(key: PreferencesKeys.suggestedLocalization, { current in 45 | if let current = current as? SuggestedLocalizationEntry { 46 | if current.languageCode == languageCode, !current.isSeen { 47 | return SuggestedLocalizationEntry(languageCode: languageCode, isSeen: true) 48 | } 49 | } else { 50 | return SuggestedLocalizationEntry(languageCode: languageCode, isSeen: true) 51 | } 52 | return current 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TelegramCore/SupportPeerId.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) 2 | import PostboxMac 3 | import SwiftSignalKitMac 4 | import MtProtoKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | import MtProtoKitDynamic 9 | #endif 10 | 11 | 12 | public func supportPeerId(account:Account) -> Signal { 13 | return account.network.request(Api.functions.help.getSupport()) 14 | |> map(Optional.init) 15 | |> `catch` { _ in 16 | return Signal.single(nil) 17 | } 18 | |> mapToSignal { support -> Signal in 19 | if let support = support { 20 | switch support { 21 | case let .support(phoneNumber: _, user: user): 22 | let user = TelegramUser(user: user) 23 | return account.postbox.transaction { transaction -> PeerId in 24 | updatePeers(transaction: transaction, peers: [user], update: { (previous, updated) -> Peer? in 25 | return updated 26 | }) 27 | return user.id 28 | } 29 | } 30 | } 31 | return .single(nil) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizeChatInputStateOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | final class SynchronizeChatInputStateOperation: PostboxCoding { 9 | let previousState: SynchronizeableChatInputState? 10 | 11 | init(previousState: SynchronizeableChatInputState?) { 12 | self.previousState = previousState 13 | } 14 | 15 | init(decoder: PostboxDecoder) { 16 | self.previousState = decoder.decodeObjectForKey("p", decoder: { SynchronizeableChatInputState(decoder: $0) }) as? SynchronizeableChatInputState 17 | } 18 | 19 | func encode(_ encoder: PostboxEncoder) { 20 | if let previousState = self.previousState { 21 | encoder.encodeObject(previousState, forKey: "p") 22 | } else { 23 | encoder.encodeNil(forKey: "p") 24 | } 25 | } 26 | } 27 | 28 | func addSynchronizeChatInputStateOperation(transaction: Transaction, peerId: PeerId) { 29 | var updateLocalIndex: Int32? 30 | let tag: PeerOperationLogTag = OperationLogTags.SynchronizeChatInputStates 31 | 32 | var previousOperation: SynchronizeChatInputStateOperation? 33 | transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in 34 | updateLocalIndex = entry.tagLocalIndex 35 | if let operation = entry.contents as? SynchronizeChatInputStateOperation { 36 | previousOperation = operation 37 | } 38 | return false 39 | }) 40 | var previousState: SynchronizeableChatInputState? 41 | if let previousOperation = previousOperation { 42 | previousState = previousOperation.previousState 43 | } else if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState { 44 | previousState = peerChatInterfaceState.synchronizeableInputState 45 | } 46 | let operationContents = SynchronizeChatInputStateOperation(previousState: previousState) 47 | if let updateLocalIndex = updateLocalIndex { 48 | let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: updateLocalIndex) 49 | } 50 | transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) 51 | } 52 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizeConsumeMessageContentsOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | final class SynchronizeConsumeMessageContentsOperation: PostboxCoding { 9 | let messageIds: [MessageId] 10 | 11 | init(messageIds: [MessageId]) { 12 | self.messageIds = messageIds 13 | } 14 | 15 | init(decoder: PostboxDecoder) { 16 | self.messageIds = MessageId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("i")!) 17 | } 18 | 19 | func encode(_ encoder: PostboxEncoder) { 20 | let buffer = WriteBuffer() 21 | MessageId.encodeArrayToBuffer(self.messageIds, buffer: buffer) 22 | encoder.encodeBytes(buffer, forKey: "i") 23 | } 24 | } 25 | 26 | func addSynchronizeConsumeMessageContentsOperation(transaction: Transaction, messageIds: [MessageId]) { 27 | for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(messageIds)) { 28 | var updateLocalIndex: Int32? 29 | /*transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, { entry in 30 | updateLocalIndex = entry.tagLocalIndex 31 | return false 32 | })*/ 33 | let operationContents = SynchronizeConsumeMessageContentsOperation(messageIds: messageIds) 34 | if let updateLocalIndex = updateLocalIndex { 35 | let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: updateLocalIndex) 36 | } 37 | transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizeEmojiKeywordsOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | final class SynchronizeEmojiKeywordsOperation: PostboxCoding { 9 | let inputLanguageCode: String 10 | let languageCode: String? 11 | let fromVersion: Int32? 12 | 13 | init(inputLanguageCode: String, languageCode: String?, fromVersion: Int32?) { 14 | self.inputLanguageCode = inputLanguageCode 15 | self.languageCode = languageCode 16 | self.fromVersion = fromVersion 17 | } 18 | 19 | init(decoder: PostboxDecoder) { 20 | self.inputLanguageCode = decoder.decodeStringForKey("ilc", orElse: "") 21 | self.languageCode = decoder.decodeOptionalStringForKey("lc") 22 | self.fromVersion = decoder.decodeOptionalInt32ForKey("v") 23 | } 24 | 25 | func encode(_ encoder: PostboxEncoder) { 26 | encoder.encodeString(self.inputLanguageCode, forKey: "ilc") 27 | if let languageCode = self.languageCode { 28 | encoder.encodeString(languageCode, forKey: "lc") 29 | } else { 30 | encoder.encodeNil(forKey: "lc") 31 | } 32 | if let fromVersion = self.fromVersion { 33 | encoder.encodeInt32(fromVersion, forKey: "v") 34 | } else { 35 | encoder.encodeNil(forKey: "v") 36 | } 37 | } 38 | } 39 | 40 | func addSynchronizeEmojiKeywordsOperation(transaction: Transaction, inputLanguageCode: String, languageCode: String?, fromVersion: Int32?) { 41 | let tag = OperationLogTags.SynchronizeEmojiKeywords 42 | let peerId = PeerId(emojiKeywordColletionIdForCode(inputLanguageCode).id) 43 | 44 | var hasExistingOperation = false 45 | transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag) { entry -> Bool in 46 | hasExistingOperation = true 47 | return false 48 | } 49 | 50 | guard !hasExistingOperation else { 51 | return 52 | } 53 | let operationContents = SynchronizeEmojiKeywordsOperation(inputLanguageCode: inputLanguageCode, languageCode: languageCode, fromVersion: fromVersion) 54 | transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) 55 | } 56 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizeLocalizationUpdatesOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | final class SynchronizeLocalizationUpdatesOperation: PostboxCoding { 11 | init() { 12 | } 13 | 14 | init(decoder: PostboxDecoder) { 15 | } 16 | 17 | func encode(_ encoder: PostboxEncoder) { 18 | } 19 | } 20 | 21 | func addSynchronizeLocalizationUpdatesOperation(transaction: Transaction) { 22 | let tag: PeerOperationLogTag = OperationLogTags.SynchronizeLocalizationUpdates 23 | let peerId = PeerId(namespace: 0, id: 0) 24 | 25 | var topLocalIndex: Int32? 26 | transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in 27 | topLocalIndex = entry.tagLocalIndex 28 | return false 29 | }) 30 | 31 | if let topLocalIndex = topLocalIndex { 32 | let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) 33 | } 34 | 35 | transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeLocalizationUpdatesOperation()) 36 | } 37 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizeMarkAllUnseenPersonalMessagesOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | final class SynchronizeMarkAllUnseenPersonalMessagesOperation: PostboxCoding { 11 | let maxId: MessageId.Id 12 | 13 | init(maxId: MessageId.Id) { 14 | self.maxId = maxId 15 | } 16 | 17 | init(decoder: PostboxDecoder) { 18 | self.maxId = decoder.decodeInt32ForKey("maxId", orElse: Int32.min + 1) 19 | } 20 | 21 | func encode(_ encoder: PostboxEncoder) { 22 | encoder.encodeInt32(self.maxId, forKey: "maxId") 23 | } 24 | } 25 | 26 | func addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: Transaction, peerId: PeerId, maxId: MessageId.Id) { 27 | let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkAllUnseenPersonalMessages 28 | 29 | var topLocalIndex: Int32? 30 | var currentMaxId: MessageId.Id? 31 | transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in 32 | topLocalIndex = entry.tagLocalIndex 33 | if let operation = entry.contents as? SynchronizeMarkAllUnseenPersonalMessagesOperation { 34 | currentMaxId = operation.maxId 35 | } 36 | return false 37 | }) 38 | 39 | if let topLocalIndex = topLocalIndex { 40 | if let currentMaxId = currentMaxId, currentMaxId >= maxId { 41 | return 42 | } 43 | let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex) 44 | } 45 | 46 | transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeMarkAllUnseenPersonalMessagesOperation(maxId: maxId)) 47 | } 48 | -------------------------------------------------------------------------------- /TelegramCore/SynchronizePinnedChatsOperation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | private struct PreviousPeerItemId: PostboxCoding { 9 | let id: PinnedItemId 10 | 11 | init(_ id: PinnedItemId) { 12 | self.id = id 13 | } 14 | 15 | init(decoder: PostboxDecoder) { 16 | switch decoder.decodeInt32ForKey("_t", orElse: 0) { 17 | case 0: 18 | self.id = .peer(PeerId(decoder.decodeInt64ForKey("i", orElse: 0))) 19 | default: 20 | preconditionFailure() 21 | } 22 | } 23 | 24 | func encode(_ encoder: PostboxEncoder) { 25 | switch self.id { 26 | case let .peer(peerId): 27 | encoder.encodeInt32(0, forKey: "_t") 28 | encoder.encodeInt64(peerId.toInt64(), forKey: "i") 29 | } 30 | } 31 | } 32 | 33 | final class SynchronizePinnedChatsOperation: PostboxCoding { 34 | let previousItemIds: [PinnedItemId] 35 | 36 | init(previousItemIds: [PinnedItemId]) { 37 | self.previousItemIds = previousItemIds 38 | } 39 | 40 | init(decoder: PostboxDecoder) { 41 | let wrappedIds: [PreviousPeerItemId] = decoder.decodeObjectArrayWithDecoderForKey("previousItemIds") 42 | self.previousItemIds = wrappedIds.map { $0.id } 43 | } 44 | 45 | func encode(_ encoder: PostboxEncoder) { 46 | encoder.encodeObjectArray(self.previousItemIds.map(PreviousPeerItemId.init), forKey: "previousItemIds") 47 | } 48 | } 49 | 50 | func addSynchronizePinnedChatsOperation(transaction: Transaction, groupId: PeerGroupId) { 51 | let rawId: Int32 = groupId.rawValue 52 | var previousItemIds = transaction.getPinnedItemIds(groupId: groupId) 53 | var updateLocalIndex: Int32? 54 | 55 | transaction.operationLogEnumerateEntries(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, { entry in 56 | updateLocalIndex = entry.tagLocalIndex 57 | if let contents = entry.contents as? SynchronizePinnedChatsOperation { 58 | previousItemIds = contents.previousItemIds 59 | } 60 | return false 61 | }) 62 | let operationContents = SynchronizePinnedChatsOperation(previousItemIds: previousItemIds) 63 | if let updateLocalIndex = updateLocalIndex { 64 | let _ = transaction.operationLogRemoveEntry(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: updateLocalIndex) 65 | } 66 | transaction.operationLogAddEntry(peerId: PeerId(namespace: 0, id: rawId), tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) 67 | } 68 | -------------------------------------------------------------------------------- /TelegramCore/TelegramCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // TelegramCore.h 3 | // TelegramCore 4 | // 5 | // Created by Peter on 8/1/16. 6 | // Copyright © 2016 Peter. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TelegramCore. 12 | FOUNDATION_EXPORT double TelegramCoreVersionNumber; 13 | 14 | //! Project version string for TelegramCore. 15 | FOUNDATION_EXPORT const unsigned char TelegramCoreVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | -------------------------------------------------------------------------------- /TelegramCore/TelegramCoreIncludes.h: -------------------------------------------------------------------------------- 1 | #ifndef TelegramCoreIncludes_h 2 | #define TelegramCoreIncludes_h 3 | 4 | #import "Crypto.h" 5 | #import "Reachability.h" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /TelegramCore/TelegramCorePrivate/module.modulemap: -------------------------------------------------------------------------------- 1 | module TelegramCorePrivateModule { 2 | header "../../third-party/libphonenumber-iOS/NBPhoneNumber.h" 3 | header "../../third-party/libphonenumber-iOS/NBPhoneNumberUtil.h" 4 | header "../../third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h" 5 | header "../NetworkLogging.h" 6 | header "../MonotonicTime.h" 7 | header "../TelegramCoreIncludes.h" 8 | } 9 | -------------------------------------------------------------------------------- /TelegramCore/TelegramMediaContact.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class TelegramMediaContact: Media { 9 | public let id: MediaId? = nil 10 | public let firstName: String 11 | public let lastName: String 12 | public let phoneNumber: String 13 | public let peerId: PeerId? 14 | public let vCardData: String? 15 | 16 | public let peerIds: [PeerId] 17 | 18 | public init(firstName: String, lastName: String, phoneNumber: String, peerId: PeerId?, vCardData: String?) { 19 | self.firstName = firstName 20 | self.lastName = lastName 21 | self.phoneNumber = phoneNumber 22 | self.peerId = peerId 23 | self.vCardData = vCardData 24 | if let peerId = peerId { 25 | self.peerIds = [peerId] 26 | } else { 27 | self.peerIds = [] 28 | } 29 | } 30 | 31 | public init(decoder: PostboxDecoder) { 32 | self.firstName = decoder.decodeStringForKey("n.f", orElse: "") 33 | self.lastName = decoder.decodeStringForKey("n.l", orElse: "") 34 | self.phoneNumber = decoder.decodeStringForKey("pn", orElse: "") 35 | if let peerIdValue = decoder.decodeOptionalInt64ForKey("p") { 36 | self.peerId = PeerId(peerIdValue) 37 | self.peerIds = [PeerId(peerIdValue)] 38 | } else { 39 | self.peerId = nil 40 | self.peerIds = [] 41 | } 42 | self.vCardData = decoder.decodeOptionalStringForKey("vc") 43 | } 44 | 45 | public func encode(_ encoder: PostboxEncoder) { 46 | encoder.encodeString(self.firstName, forKey: "n.f") 47 | encoder.encodeString(self.lastName, forKey: "n.l") 48 | encoder.encodeString(self.phoneNumber, forKey: "pn") 49 | if let peerId = self.peerId { 50 | encoder.encodeInt64(peerId.toInt64(), forKey: "p") 51 | } 52 | if let vCardData = self.vCardData { 53 | encoder.encodeString(vCardData, forKey: "vc") 54 | } else { 55 | encoder.encodeNil(forKey: "vc") 56 | } 57 | } 58 | 59 | public func isEqual(to other: Media) -> Bool { 60 | if let other = other as? TelegramMediaContact { 61 | 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 { 62 | return true 63 | } 64 | } 65 | return false 66 | } 67 | 68 | public func isSemanticallyEqual(to other: Media) -> Bool { 69 | return self.isEqual(to: other) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TelegramCore/TelegramMediaExpiredContent.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public enum TelegramMediaExpiredContentData: Int32 { 9 | case image 10 | case file 11 | } 12 | 13 | public final class TelegramMediaExpiredContent: Media { 14 | public let data: TelegramMediaExpiredContentData 15 | 16 | public let id: MediaId? = nil 17 | public let peerIds: [PeerId] = [] 18 | 19 | public init(data: TelegramMediaExpiredContentData) { 20 | self.data = data 21 | } 22 | 23 | public init(decoder: PostboxDecoder) { 24 | self.data = TelegramMediaExpiredContentData(rawValue: decoder.decodeInt32ForKey("d", orElse: 0))! 25 | } 26 | 27 | public func encode(_ encoder: PostboxEncoder) { 28 | encoder.encodeInt32(self.data.rawValue, forKey: "d") 29 | } 30 | 31 | public func isEqual(to other: Media) -> Bool { 32 | if let other = other as? TelegramMediaExpiredContent { 33 | return self.data == other.data 34 | } else { 35 | return false 36 | } 37 | } 38 | 39 | public func isSemanticallyEqual(to other: Media) -> Bool { 40 | return self.isEqual(to: other) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TelegramCore/TelegramMediaResource.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public protocol TelegramMediaResource: MediaResource, PostboxCoding { 9 | } 10 | -------------------------------------------------------------------------------- /TelegramCore/TeleramMediaUnsupported.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public final class TelegramMediaUnsupported: Media { 9 | public let id: MediaId? = nil 10 | public let peerIds: [PeerId] = [] 11 | 12 | init() { 13 | } 14 | 15 | public init(decoder: PostboxDecoder) { 16 | } 17 | 18 | public func encode(_ encoder: PostboxEncoder) { 19 | } 20 | 21 | public func isEqual(to other: Media) -> Bool { 22 | if other is TelegramMediaUnsupported { 23 | return true 24 | } 25 | return false 26 | } 27 | 28 | public func isSemanticallyEqual(to other: Media) -> Bool { 29 | return self.isEqual(to: other) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TelegramCore/ToggleChannelSignatures.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public func toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal { 13 | return account.postbox.transaction { transaction -> Signal in 14 | if let peer = transaction.getPeer(peerId) as? TelegramChannel, let inputChannel = apiInputChannel(peer) { 15 | return account.network.request(Api.functions.channels.toggleSignatures(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> retryRequest |> map { updates -> Void in 16 | account.stateManager.addUpdates(updates) 17 | } 18 | } else { 19 | return .complete() 20 | } 21 | } |> switchToLatest 22 | } 23 | -------------------------------------------------------------------------------- /TelegramCore/UpdateAccountPeerName.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public func updateAccountPeerName(account: Account, firstName: String, lastName: String) -> Signal { 13 | return account.network.request(Api.functions.account.updateProfile(flags: (1 << 0) | (1 << 1), firstName: firstName, lastName: lastName, about: nil)) 14 | |> map { result -> Api.User? in 15 | return result 16 | } 17 | |> `catch` { _ in 18 | return .single(nil) 19 | } 20 | |> mapToSignal { result -> Signal in 21 | return account.postbox.transaction { transaction -> Void in 22 | if let result = result { 23 | let peer = TelegramUser(user: result) 24 | updatePeers(transaction: transaction, peers: [peer], update: { $1 }) 25 | } 26 | } 27 | } 28 | } 29 | 30 | public enum UpdateAboutError { 31 | case generic 32 | } 33 | 34 | 35 | public func updateAbout(account: Account, about: String?) -> Signal { 36 | return account.network.request(Api.functions.account.updateProfile(flags: about == nil ? 0 : (1 << 2), firstName: nil, lastName: nil, about: about)) 37 | |> mapError { _ -> UpdateAboutError in 38 | return .generic 39 | } 40 | |> mapToSignal { apiUser -> Signal in 41 | return account.postbox.transaction { transaction -> Void in 42 | transaction.updatePeerCachedData(peerIds: Set([account.peerId]), update: { _, current in 43 | if let current = current as? CachedUserData { 44 | return current.withUpdatedAbout(about) 45 | } else { 46 | return current 47 | } 48 | }) 49 | } |> mapError { _ -> UpdateAboutError in return .generic } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /TelegramCore/UpdateContactName.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | import MtProtoKitMac 6 | #else 7 | import Postbox 8 | import SwiftSignalKit 9 | import MtProtoKitDynamic 10 | #endif 11 | 12 | public enum UpdateContactNameError { 13 | case generic 14 | } 15 | 16 | public func updateContactName(account: Account, peerId: PeerId, firstName: String, lastName: String) -> Signal { 17 | return account.postbox.transaction { transaction -> Signal in 18 | if let peer = transaction.getPeer(peerId) as? TelegramUser, let phone = peer.phone, !phone.isEmpty { 19 | return account.network.request(Api.functions.contacts.importContacts(contacts: [Api.InputContact.inputPhoneContact(clientId: 1, phone: phone, firstName: firstName, lastName: lastName)])) 20 | |> mapError { _ -> UpdateContactNameError in 21 | return .generic 22 | } 23 | |> mapToSignal { result -> Signal in 24 | return account.postbox.transaction { transaction -> Void in 25 | switch result { 26 | case let .importedContacts(_, _, _, users): 27 | if let first = users.first { 28 | let user = TelegramUser(user: first) 29 | updatePeers(transaction: transaction, peers: [user], update: { _, updated in 30 | return updated 31 | }) 32 | } 33 | } 34 | } |> mapError { _ -> UpdateContactNameError in return .generic } 35 | } 36 | } else { 37 | return .fail(.generic) 38 | } 39 | } |> mapError { _ -> UpdateContactNameError in return .generic } |> switchToLatest 40 | } 41 | -------------------------------------------------------------------------------- /TelegramCore/UpdateGroupSpecificStickerset.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | 11 | public enum UpdateGroupSpecificStickersetError { 12 | case generic 13 | } 14 | 15 | public func updateGroupSpecificStickerset(postbox: Postbox, network: Network, peerId: PeerId, info: StickerPackCollectionInfo?) -> Signal { 16 | return postbox.loadedPeerWithId(peerId) 17 | |> introduceError(UpdateGroupSpecificStickersetError.self) 18 | |> mapToSignal { peer -> Signal in 19 | let inputStickerset: Api.InputStickerSet 20 | if let info = info { 21 | inputStickerset = Api.InputStickerSet.inputStickerSetShortName(shortName: info.shortName) 22 | } else { 23 | inputStickerset = Api.InputStickerSet.inputStickerSetEmpty 24 | } 25 | if let inputChannel = apiInputChannel(peer) { 26 | return network.request(Api.functions.channels.setStickers(channel: inputChannel, stickerset: inputStickerset)) 27 | |> mapError { _ -> UpdateGroupSpecificStickersetError in 28 | return .generic 29 | } 30 | |> mapToSignal { value -> Signal in 31 | switch value { 32 | case .boolTrue: 33 | return postbox.transaction { transaction -> Void in 34 | return transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current -> CachedPeerData? in 35 | return (current as? CachedChannelData)?.withUpdatedStickerPack(info) 36 | }) 37 | } 38 | |> introduceError(UpdateGroupSpecificStickersetError.self) 39 | default: 40 | return .complete() 41 | } 42 | } 43 | } 44 | return .complete() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TelegramCore/UpdateMessageMedia.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | func updateMessageMedia(transaction: Transaction, id: MediaId, media: Media?) { 9 | let updatedMessageIndices = transaction.updateMedia(id, update: media) 10 | for index in updatedMessageIndices { 11 | transaction.updateMessage(index.id, update: { currentMessage in 12 | var textEntities: [MessageTextEntity]? 13 | for attribute in currentMessage.attributes { 14 | if let attribute = attribute as? TextEntitiesMessageAttribute { 15 | textEntities = attribute.entities 16 | break 17 | } 18 | } 19 | let (tags, _) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: currentMessage.attributes, media: currentMessage.media, textEntities: textEntities) 20 | if tags == currentMessage.tags { 21 | return .skip 22 | } 23 | 24 | var storeForwardInfo: StoreMessageForwardInfo? 25 | if let forwardInfo = currentMessage.forwardInfo { 26 | storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) 27 | } 28 | 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)) 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TelegramCore/UpdatePeerChatInterfaceState.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | import SwiftSignalKitMac 5 | #else 6 | import Postbox 7 | import SwiftSignalKit 8 | #endif 9 | 10 | public func updatePeerChatInterfaceState(account: Account, peerId: PeerId, state: SynchronizeableChatInterfaceState) -> Signal { 11 | return account.postbox.transaction { transaction -> Void in 12 | let currentInputState = (transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState)?.synchronizeableInputState 13 | let updatedInputState = state.synchronizeableInputState 14 | 15 | if currentInputState != updatedInputState { 16 | if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup { 17 | addSynchronizeChatInputStateOperation(transaction: transaction, peerId: peerId) 18 | } 19 | } 20 | transaction.updatePeerChatInterfaceState(peerId, update: { _ in 21 | return state 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TelegramCore/ViewCountMessageAttribute.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public class ViewCountMessageAttribute: MessageAttribute { 9 | public let count: Int 10 | 11 | public var associatedMessageIds: [MessageId] = [] 12 | 13 | init(count: Int) { 14 | self.count = count 15 | } 16 | 17 | required public init(decoder: PostboxDecoder) { 18 | self.count = Int(decoder.decodeInt32ForKey("c", orElse: 0)) 19 | } 20 | 21 | public func encode(_ encoder: PostboxEncoder) { 22 | encoder.encodeInt32(Int32(self.count), forKey: "c") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TelegramCore/VoipConfiguration.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if os(macOS) 3 | import PostboxMac 4 | #else 5 | import Postbox 6 | #endif 7 | 8 | public enum VoiceCallP2PMode: Int32 { 9 | case never = 0 10 | case contacts = 1 11 | case always = 2 12 | } 13 | 14 | public struct VoipConfiguration: PreferencesEntry, Equatable { 15 | public var serializedData: String? 16 | 17 | public static var defaultValue: VoipConfiguration { 18 | return VoipConfiguration(serializedData: nil) 19 | } 20 | 21 | init(serializedData: String?) { 22 | self.serializedData = serializedData 23 | } 24 | 25 | public init(decoder: PostboxDecoder) { 26 | self.serializedData = decoder.decodeOptionalStringForKey("serializedData") 27 | } 28 | 29 | public func encode(_ encoder: PostboxEncoder) { 30 | if let serializedData = self.serializedData { 31 | encoder.encodeString(serializedData, forKey: "serializedData") 32 | } else { 33 | encoder.encodeNil(forKey: "serializedData") 34 | } 35 | } 36 | 37 | public func isEqual(to: PreferencesEntry) -> Bool { 38 | guard let to = to as? VoipConfiguration else { 39 | return false 40 | } 41 | return self == to 42 | } 43 | } 44 | 45 | public func currentVoipConfiguration(transaction: Transaction) -> VoipConfiguration { 46 | if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.voipConfiguration) as? VoipConfiguration { 47 | return entry 48 | } else { 49 | return VoipConfiguration.defaultValue 50 | } 51 | } 52 | 53 | func updateVoipConfiguration(transaction: Transaction, _ f: (VoipConfiguration) -> VoipConfiguration) { 54 | let current = currentVoipConfiguration(transaction: transaction) 55 | let updated = f(current) 56 | if updated != current { 57 | transaction.setPreferencesEntry(key: PreferencesKeys.voipConfiguration, value: updated) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /TelegramCore/module.private-mac.modulemap: -------------------------------------------------------------------------------- 1 | module TelegramCoreMac.TelegramCorePrivate { 2 | export * 3 | } 4 | -------------------------------------------------------------------------------- /TelegramCore/module.private.modulemap: -------------------------------------------------------------------------------- 1 | module TelegramCore.TelegramCorePrivate { 2 | export * 3 | } 4 | -------------------------------------------------------------------------------- /TelegramCoreMac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2016 Peter. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /TelegramCoreMac/TelegramCoreMac.h: -------------------------------------------------------------------------------- 1 | // 2 | // TelegramCoreMac.h 3 | // TelegramCoreMac 4 | // 5 | // Created by Peter on 9/5/16. 6 | // Copyright © 2016 Peter. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TelegramCoreMac. 12 | FOUNDATION_EXPORT double TelegramCoreMacVersionNumber; 13 | 14 | //! Project version string for TelegramCoreMac. 15 | FOUNDATION_EXPORT const unsigned char TelegramCoreMacVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TelegramCoreTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TelegramCoreTests/TelegramCoreTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TelegramCoreTests.m 3 | // TelegramCoreTests 4 | // 5 | // Created by Peter on 8/1/16. 6 | // Copyright © 2016 Peter. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TelegramCoreTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TelegramCoreTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBAsYouTypeFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBAsYouTypeFormatter.h 3 | // libPhoneNumber 4 | // 5 | // Created by ishtar on 13. 2. 25.. 6 | // 7 | 8 | #import 9 | 10 | 11 | @class NBAsYouTypeFormatter; 12 | 13 | 14 | @interface NBAsYouTypeFormatter : NSObject 15 | 16 | - (id)initWithRegionCode:(NSString *)regionCode; 17 | - (id)initWithRegionCodeForTest:(NSString *)regionCode; 18 | - (id)initWithRegionCode:(NSString *)regionCode bundle:(NSBundle *)bundle; 19 | - (id)initWithRegionCodeForTest:(NSString *)regionCode bundle:(NSBundle *)bundle; 20 | 21 | - (NSString *)inputString:(NSString *)string; 22 | - (NSString *)inputStringAndRememberPosition:(NSString *)string; 23 | 24 | - (NSString *)inputDigit:(NSString*)nextChar; 25 | - (NSString *)inputDigitAndRememberPosition:(NSString*)nextChar; 26 | 27 | - (NSString *)removeLastDigit; 28 | - (NSString *)removeLastDigitAndRememberPosition; 29 | 30 | - (NSInteger)getRememberedPosition; 31 | 32 | - (void)clear; 33 | 34 | @property (nonatomic, assign, readonly) BOOL isSuccessfulFormatting; 35 | 36 | @property (nonatomic, strong, readonly) NSString *regionPrefix; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBMetadataCoreMapper.h: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) 2 | 3 | #import 4 | 5 | @interface NBMetadataCoreMapper : NSObject 6 | 7 | + (NSArray *)ISOCodeFromCallingNumber:(NSString *)key; 8 | 9 | @end 10 | 11 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBMetadataCoreTest.h: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) 2 | 3 | #import 4 | #import "NBPhoneMetaData.h" 5 | 6 | @interface NBPhoneMetadataTestAD : NBPhoneMetaData 7 | @end 8 | 9 | @interface NBPhoneMetadataTestBR : NBPhoneMetaData 10 | @end 11 | 12 | @interface NBPhoneMetadataTestAU : NBPhoneMetaData 13 | @end 14 | 15 | @interface NBPhoneMetadataTestBB : NBPhoneMetaData 16 | @end 17 | 18 | @interface NBPhoneMetadataTestAE : NBPhoneMetaData 19 | @end 20 | 21 | @interface NBPhoneMetadataTestCX : NBPhoneMetaData 22 | @end 23 | 24 | @interface NBPhoneMetadataTestBS : NBPhoneMetaData 25 | @end 26 | 27 | @interface NBPhoneMetadataTestDE : NBPhoneMetaData 28 | @end 29 | 30 | @interface NBPhoneMetadataTestKR : NBPhoneMetaData 31 | @end 32 | 33 | @interface NBPhoneMetadataTestNZ : NBPhoneMetaData 34 | @end 35 | 36 | @interface NBPhoneMetadataTestPL : NBPhoneMetaData 37 | @end 38 | 39 | @interface NBPhoneMetadataTestSE : NBPhoneMetaData 40 | @end 41 | 42 | @interface NBPhoneMetadataTestCA : NBPhoneMetaData 43 | @end 44 | 45 | @interface NBPhoneMetadataTestAO : NBPhoneMetaData 46 | @end 47 | 48 | @interface NBPhoneMetadataTest800 : NBPhoneMetaData 49 | @end 50 | 51 | @interface NBPhoneMetadataTestYT : NBPhoneMetaData 52 | @end 53 | 54 | @interface NBPhoneMetadataTestFR : NBPhoneMetaData 55 | @end 56 | 57 | @interface NBPhoneMetadataTestGG : NBPhoneMetaData 58 | @end 59 | 60 | @interface NBPhoneMetadataTestHU : NBPhoneMetaData 61 | @end 62 | 63 | @interface NBPhoneMetadataTestSG : NBPhoneMetaData 64 | @end 65 | 66 | @interface NBPhoneMetadataTestJP : NBPhoneMetaData 67 | @end 68 | 69 | @interface NBPhoneMetadataTestCC : NBPhoneMetaData 70 | @end 71 | 72 | @interface NBPhoneMetadataTestMX : NBPhoneMetaData 73 | @end 74 | 75 | @interface NBPhoneMetadataTestUS : NBPhoneMetaData 76 | @end 77 | 78 | @interface NBPhoneMetadataTestIT : NBPhoneMetaData 79 | @end 80 | 81 | @interface NBPhoneMetadataTestAR : NBPhoneMetaData 82 | @end 83 | 84 | @interface NBPhoneMetadataTest979 : NBPhoneMetaData 85 | @end 86 | 87 | @interface NBPhoneMetadataTestGB : NBPhoneMetaData 88 | @end 89 | 90 | @interface NBPhoneMetadataTestBY : NBPhoneMetaData 91 | @end 92 | 93 | @interface NBPhoneMetadataTestCN : NBPhoneMetaData 94 | @end 95 | 96 | @interface NBPhoneMetadataTestRE : NBPhoneMetaData 97 | @end 98 | 99 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBMetadataCoreTestMapper.h: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT (This file was auto-generated from NBPhoneMetaDataGenerator) 2 | 3 | #import 4 | 5 | @interface NBMetadataCoreTestMapper : NSObject 6 | 7 | + (NSArray *)ISOCodeFromCallingNumber:(NSString *)key; 8 | 9 | @end 10 | 11 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBMetadataHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBMetadataHelper.h 3 | // libPhoneNumber 4 | // 5 | // Created by tabby on 2015. 2. 8.. 6 | // Copyright (c) 2015년 ohtalk.me. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NBPhoneNumberDefines.h" 11 | 12 | 13 | @class NBPhoneMetaData; 14 | 15 | @interface NBMetadataHelper : NSObject 16 | 17 | + (BOOL)hasValue:(NSString *)string; 18 | 19 | - (NSDictionary *)CCode2CNMap; 20 | 21 | - (NSArray *)getAllMetadata; 22 | 23 | - (NBPhoneMetaData *)getMetadataForNonGeographicalRegion:(NSNumber *)countryCallingCode; 24 | - (NBPhoneMetaData *)getMetadataForRegion:(NSString *)regionCode; 25 | 26 | - (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber; 27 | - (NSString *)countryCodeFromRegionCode:(NSString *)regionCode; 28 | 29 | - (NSString *)stringByTrimming:(NSString *)aString; 30 | - (NSString *)normalizeNonBreakingSpace:(NSString *)aString; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBNumberFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBPhoneNumberFormat.h 3 | // libPhoneNumber 4 | // 5 | // 6 | 7 | #import 8 | 9 | 10 | @interface NBNumberFormat : NSObject 11 | 12 | // from phonemetadata.pb.js 13 | /* 1 */ @property (nonatomic, strong) NSString *pattern; 14 | /* 2 */ @property (nonatomic, strong) NSString *format; 15 | /* 3 */ @property (nonatomic, strong) NSMutableArray *leadingDigitsPatterns; 16 | /* 4 */ @property (nonatomic, strong) NSString *nationalPrefixFormattingRule; 17 | /* 6 */ @property (nonatomic, assign) BOOL nationalPrefixOptionalWhenFormatting; 18 | /* 5 */ @property (nonatomic, strong) NSString *domesticCarrierCodeFormattingRule; 19 | 20 | - (id)initWithPattern:(NSString *)pattern withFormat:(NSString *)format withLeadingDigitsPatterns:(NSMutableArray *)leadingDigitsPatterns withNationalPrefixFormattingRule:(NSString *)nationalPrefixFormattingRule whenFormatting:(BOOL)nationalPrefixOptionalWhenFormatting withDomesticCarrierCodeFormattingRule:(NSString *)domesticCarrierCodeFormattingRule; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBPhoneMetaData.h: -------------------------------------------------------------------------------- 1 | // 2 | // M2PhoneMetaData.h 3 | // libPhoneNumber 4 | // 5 | // 6 | 7 | #import 8 | 9 | 10 | @class NBPhoneNumberDesc, NBNumberFormat; 11 | 12 | @interface NBPhoneMetaData : NSObject 13 | 14 | // from phonemetadata.pb.js 15 | /* 1 */ @property (nonatomic, strong) NBPhoneNumberDesc *generalDesc; 16 | /* 2 */ @property (nonatomic, strong) NBPhoneNumberDesc *fixedLine; 17 | /* 3 */ @property (nonatomic, strong) NBPhoneNumberDesc *mobile; 18 | /* 4 */ @property (nonatomic, strong) NBPhoneNumberDesc *tollFree; 19 | /* 5 */ @property (nonatomic, strong) NBPhoneNumberDesc *premiumRate; 20 | /* 6 */ @property (nonatomic, strong) NBPhoneNumberDesc *sharedCost; 21 | /* 7 */ @property (nonatomic, strong) NBPhoneNumberDesc *personalNumber; 22 | /* 8 */ @property (nonatomic, strong) NBPhoneNumberDesc *voip; 23 | /* 21 */ @property (nonatomic, strong) NBPhoneNumberDesc *pager; 24 | /* 25 */ @property (nonatomic, strong) NBPhoneNumberDesc *uan; 25 | /* 27 */ @property (nonatomic, strong) NBPhoneNumberDesc *emergency; 26 | /* 28 */ @property (nonatomic, strong) NBPhoneNumberDesc *voicemail; 27 | /* 24 */ @property (nonatomic, strong) NBPhoneNumberDesc *noInternationalDialling; 28 | /* 9 */ @property (nonatomic, strong) NSString *codeID; 29 | /* 10 */ @property (nonatomic, strong) NSNumber *countryCode; 30 | /* 11 */ @property (nonatomic, strong) NSString *internationalPrefix; 31 | /* 17 */ @property (nonatomic, strong) NSString *preferredInternationalPrefix; 32 | /* 12 */ @property (nonatomic, strong) NSString *nationalPrefix; 33 | /* 13 */ @property (nonatomic, strong) NSString *preferredExtnPrefix; 34 | /* 15 */ @property (nonatomic, strong) NSString *nationalPrefixForParsing; 35 | /* 16 */ @property (nonatomic, strong) NSString *nationalPrefixTransformRule; 36 | /* 18 */ @property (nonatomic, assign) BOOL sameMobileAndFixedLinePattern; 37 | /* 19 */ @property (nonatomic, strong) NSMutableArray *numberFormats; 38 | /* 20 */ @property (nonatomic, strong) NSMutableArray *intlNumberFormats; 39 | /* 22 */ @property (nonatomic, assign) BOOL mainCountryForCode; 40 | /* 23 */ @property (nonatomic, strong) NSString *leadingDigits; 41 | /* 26 */ @property (nonatomic, assign) BOOL leadingZeroPossible; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBPhoneMetaDataGenerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBPhoneMetaDataGenerator.h 3 | // libPhoneNumber 4 | // 5 | // 6 | 7 | #import 8 | 9 | 10 | @interface NBPhoneMetaDataGenerator : NSObject 11 | 12 | - (void)generateMetadataClasses; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBPhoneNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBPhoneNumber.h 3 | // libPhoneNumber 4 | // 5 | // 6 | 7 | #import 8 | #import "NBPhoneNumberDefines.h" 9 | 10 | 11 | @interface NBPhoneNumber : NSObject 12 | 13 | // from phonemetadata.pb.js 14 | /* 1 */ @property (nonatomic, strong, readwrite) NSNumber *countryCode; 15 | /* 2 */ @property (nonatomic, strong, readwrite) NSNumber *nationalNumber; 16 | /* 3 */ @property (nonatomic, strong, readwrite) NSString *extension; 17 | /* 4 */ @property (nonatomic, assign, readwrite) BOOL italianLeadingZero; 18 | /* 5 */ @property (nonatomic, strong, readwrite) NSString *rawInput; 19 | /* 6 */ @property (nonatomic, strong, readwrite) NSNumber *countryCodeSource; 20 | /* 7 */ @property (nonatomic, strong, readwrite) NSString *preferredDomesticCarrierCode; 21 | 22 | - (void)clearCountryCodeSource; 23 | - (NBECountryCodeSource)getCountryCodeSourceOrDefault; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBPhoneNumberDefines.m: -------------------------------------------------------------------------------- 1 | #import "NBPhoneNumberDefines.h" 2 | 3 | NSString * const NB_UNKNOWN_REGION = @"ZZ"; 4 | NSString * const NB_NON_BREAKING_SPACE = @"\u00a0"; 5 | NSString * const NB_PLUS_CHARS = @"++"; 6 | NSString * const NB_VALID_DIGITS_STRING = @"0-90-9٠-٩۰-۹"; 7 | NSString * const NB_REGION_CODE_FOR_NON_GEO_ENTITY = @"001"; 8 | -------------------------------------------------------------------------------- /third-party/libphonenumber-iOS/NBPhoneNumberDesc.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBPhoneNumberDesc.h 3 | // libPhoneNumber 4 | // 5 | // 6 | 7 | #import 8 | 9 | 10 | @interface NBPhoneNumberDesc : NSObject 11 | 12 | // from phonemetadata.pb.js 13 | /* 2 */ @property (nonatomic, strong, readwrite) NSString *nationalNumberPattern; 14 | /* 3 */ @property (nonatomic, strong, readwrite) NSString *possibleNumberPattern; 15 | /* 6 */ @property (nonatomic, strong, readwrite) NSString *exampleNumber; 16 | 17 | - (id)initWithNationalNumberPattern:(NSString *)nnp withPossibleNumberPattern:(NSString *)pnp withExample:(NSString *)exp; 18 | 19 | @end 20 | --------------------------------------------------------------------------------