diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index b13003e586..e2ded194e5 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + C22EE61B1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */; }; + C22EE61C1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */; }; C2366C831E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */; }; C2366C841E4F3EAA0097CCFF /* GroupReturnAndLeft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */; }; C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2366C851E4F403C0097CCFF /* AddressNames.swift */; }; @@ -17,6 +19,8 @@ C239BE981E62F0D200C2C453 /* LoadMessagesIfNecessary.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */; }; C239BE9C1E630CA700C2C453 /* UpdatePinnedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */; }; C239BE9D1E630CB300C2C453 /* UpdatePinnedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */; }; + C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C251D7421E65E50500283EDE /* StickerSetInstallation.swift */; }; + C251D7441E65E50500283EDE /* StickerSetInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C251D7421E65E50500283EDE /* StickerSetInstallation.swift */; }; C26A37EF1E5E0C41006977AC /* ChannelParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BB7C591E5C8074001527C3 /* ChannelParticipants.swift */; }; C2A315C01E2E776A00D89000 /* RequestStartBot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01749581E1092BC0057C89A /* RequestStartBot.swift */; }; D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CFF1D62255C00955575 /* ChannelState.swift */; }; @@ -428,11 +432,13 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleChannelSignatures.swift; sourceTree = ""; }; C2366C821E4F3EAA0097CCFF /* GroupReturnAndLeft.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupReturnAndLeft.swift; sourceTree = ""; }; C2366C851E4F403C0097CCFF /* AddressNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressNames.swift; sourceTree = ""; }; C2366C881E4F40480097CCFF /* SupportPeerId.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportPeerId.swift; sourceTree = ""; }; C239BE961E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadMessagesIfNecessary.swift; sourceTree = ""; }; C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePinnedMessage.swift; sourceTree = ""; }; + C251D7421E65E50500283EDE /* StickerSetInstallation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerSetInstallation.swift; sourceTree = ""; }; D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = ""; }; D00C7CCB1E3620C30080C3D5 /* CachedChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedChannelParticipants.swift; sourceTree = ""; }; D00C7CCE1E3628180080C3D5 /* UpdateCachedChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateCachedChannelParticipants.swift; sourceTree = ""; }; @@ -715,6 +721,7 @@ D021E0E11DB5401A00C6B04F /* StickerManagement.swift */, D01D6BF81E42A713006151C6 /* SearchStickers.swift */, D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */, + C251D7421E65E50500283EDE /* StickerSetInstallation.swift */, ); name = "Sticker Management"; sourceTree = ""; @@ -1117,6 +1124,7 @@ D033FEB51E61F3F900644997 /* BlockedPeers.swift */, C239BE9B1E630CA700C2C453 /* UpdatePinnedMessage.swift */, D0528E641E65C82400E2FEF5 /* UpdateContactName.swift */, + C22EE61A1E67418000334C38 /* ToggleChannelSignatures.swift */, ); name = Peers; sourceTree = ""; @@ -1346,6 +1354,7 @@ D0BC386E1E3FDAB70044D6FE /* CreateGroup.swift in Sources */, D0FA8BB31E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */, D0E305AA1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */, + C22EE61B1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */, D073CE601DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, D03B0D6B1D631A9D00955575 /* Phonebook.swift in Sources */, D0AAD1A81E32602500D5B9DE /* AutoremoveTimeoutMessageAttribute.swift in Sources */, @@ -1507,6 +1516,7 @@ D0B843C51DA7FF30005F29E1 /* NBPhoneNumber.m in Sources */, D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */, D03B0D081D62255C00955575 /* ChannelState.swift in Sources */, + C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1545,6 +1555,7 @@ D0F7B1E91E045C87007EB8A5 /* PeerCommands.swift in Sources */, D00D97C81E32901700E5C2B6 /* PeerInputActivity.swift in Sources */, D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */, + C22EE61C1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */, D0B418AC1D7E0597004562A4 /* Network.swift in Sources */, D0B844141DAB91CD005F29E1 /* PhoneNumbers.swift in Sources */, D0E305AB1E5BA02D00D7A3A2 /* ChannelBlacklist.swift in Sources */, @@ -1706,6 +1717,7 @@ D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, D0B844431DAB91FD005F29E1 /* Account.swift in Sources */, D0448CA01E27F5EB005A61A7 /* Random.swift in Sources */, + C251D7441E65E50500283EDE /* StickerSetInstallation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TelegramCore/AddPeerMember.swift b/TelegramCore/AddPeerMember.swift index 835d23d67c..61495846b1 100644 --- a/TelegramCore/AddPeerMember.swift +++ b/TelegramCore/AddPeerMember.swift @@ -89,7 +89,7 @@ public func addPeerMember(account: Account, peerId: PeerId, memberId: PeerId) -> } -public func addSupergroupMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal { +public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal { return account.postbox.modify { modifier -> Signal in var memberPeerIds:[PeerId:Peer] = [:] diff --git a/TelegramCore/ApiGroupOrChannel.swift b/TelegramCore/ApiGroupOrChannel.swift index 49a964b113..dd7a5295e7 100644 --- a/TelegramCore/ApiGroupOrChannel.swift +++ b/TelegramCore/ApiGroupOrChannel.swift @@ -83,7 +83,7 @@ public func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? { if (flags & Int32(1 << 11)) != 0 { infoFlags.insert(.messagesShouldHaveSignatures) } - info = .broadcast(TelegramChannelBroadcastInfo(flags: [])) + info = .broadcast(TelegramChannelBroadcastInfo(flags: infoFlags)) } var channelFlags = TelegramChannelFlags() diff --git a/TelegramCore/EnqueueMessage.swift b/TelegramCore/EnqueueMessage.swift index 0a216cece3..4e0bd35baf 100644 --- a/TelegramCore/EnqueueMessage.swift +++ b/TelegramCore/EnqueueMessage.swift @@ -176,7 +176,13 @@ func enqueueMessages(modifier: Modifier, account: Account, peerId: PeerId, messa if let sourceForwardInfo = sourceMessage.forwardInfo { forwardInfo = StoreMessageForwardInfo(authorId: sourceForwardInfo.author.id, sourceId: sourceForwardInfo.source?.id, sourceMessageId: sourceForwardInfo.sourceMessageId, date: sourceForwardInfo.date) } else { - forwardInfo = StoreMessageForwardInfo(authorId: author.id, sourceId: nil, sourceMessageId: nil, date: sourceMessage.timestamp) + var sourceId:PeerId? = nil + var sourceMessageId:MessageId? = nil + if let peer = messageMainPeer(sourceMessage) as? TelegramChannel, case .broadcast = peer.info { + sourceId = peer.id + sourceMessageId = sourceMessage.id + } + forwardInfo = StoreMessageForwardInfo(authorId: author.id, sourceId: sourceId, sourceMessageId: sourceMessageId, date: sourceMessage.timestamp) } storeMessages.append(StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, timestamp: timestamp, flags: flags, tags: tagsForStoreMessage(sourceMessage.media), forwardInfo: forwardInfo, authorId: account.peerId, text: sourceMessage.text, attributes: attributes, media: sourceMessage.media)) } diff --git a/TelegramCore/InvitationLinks.swift b/TelegramCore/InvitationLinks.swift index b70bccb061..29ccb0e636 100644 --- a/TelegramCore/InvitationLinks.swift +++ b/TelegramCore/InvitationLinks.swift @@ -9,11 +9,11 @@ import Foundation import MtProtoKitDynamic #endif -public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId) -> Signal { +public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted:Bool = false) -> Signal { return account.postbox.modify { modifier -> Signal in if let peer = modifier.getPeer(peerId) { if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { - if let cachedData = modifier.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil { + if let cachedData = modifier.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted { return .complete() } else { return account.network.request(Api.functions.channels.exportInvite(channel: inputChannel)) @@ -33,7 +33,7 @@ public func ensuredExistingPeerExportedInvitation(account: Account, peerId: Peer } } } else if let group = peer as? TelegramGroup { - if let cachedData = modifier.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil { + if let cachedData = modifier.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted { return .complete() } else { return account.network.request(Api.functions.messages.exportChatInvite(chatId: group.id.id)) diff --git a/TelegramCore/ReportPeer.swift b/TelegramCore/ReportPeer.swift index 62a1de80a6..eb6fe642ea 100644 --- a/TelegramCore/ReportPeer.swift +++ b/TelegramCore/ReportPeer.swift @@ -46,8 +46,67 @@ public func reportPeer(account: Account, peerId: PeerId) -> Signal switchToLatest } +public enum ReportPeerReason : Equatable { + case spam + case violence + case porno + case custom(String) +} + +public func ==(lhs:ReportPeerReason, rhs: ReportPeerReason) -> Bool { + switch lhs { + case .spam: + if case .spam = rhs { + return true + } else { + return false + } + case .violence: + if case .violence = rhs { + return true + } else { + return false + } + case .porno: + if case .porno = rhs { + return true + } else { + return false + } + case let .custom(text): + if case .custom(text) = rhs { + return true + } else { + return false + } + } +} + +private extension ReportPeerReason { + var apiReason:Api.ReportReason { + switch self { + case .spam: + return .inputReportReasonSpam + case .violence: + return .inputReportReasonViolence + case .porno: + return .inputReportReasonPornography + case let .custom(text): + return .inputReportReasonOther(text: text) + } + } +} + +public func reportPeer(account: Account, peerId:PeerId, reason:ReportPeerReason) -> Signal { + return account.postbox.modify { modifier -> Signal in + if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason)) |> mapError {_ in} |> map {_ in} + } else { + return .complete() + } + } |> switchToLatest +} -//NOT MARKING TO CLOUD, NEED REMOVE ON FUTURE public func dismissReportPeer(account: Account, peerId: PeerId) -> Signal { return account.postbox.modify { modifier -> Signal in modifier.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in diff --git a/TelegramCore/StickerManagement.swift b/TelegramCore/StickerManagement.swift index b1a5cbb510..6a7bd3e1ee 100644 --- a/TelegramCore/StickerManagement.swift +++ b/TelegramCore/StickerManagement.swift @@ -39,8 +39,15 @@ func manageStickerPacks(network: Network, postbox: Postbox) -> Signal Bool { diff --git a/TelegramCore/StickerSetInstallation.swift b/TelegramCore/StickerSetInstallation.swift new file mode 100644 index 0000000000..f8ee12d645 --- /dev/null +++ b/TelegramCore/StickerSetInstallation.swift @@ -0,0 +1,240 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + + +public enum RequestStickerSetError { + case generic + case invalid +} + +fileprivate extension Api.StickerSet { + var info:StickerPackCollectionInfo { + switch self { + case let .stickerSet(data): + + var flags:StickerPackCollectionInfoFlags = StickerPackCollectionInfoFlags() + if (data.flags & (1 << 2)) != 0 { + flags.insert(.official) + } + if (data.flags & (1 << 3)) != 0 { + flags.insert(.masks) + } + + return StickerPackCollectionInfo(id: ItemCollectionId(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: data.id), flags: flags, accessHash: data.accessHash, title: data.title, shortName: data.shortName, hash: data.hash) + } + } +} + +public enum RequestStickerSetResult { + case local(info: ItemCollectionInfo, items: [ItemCollectionItem]) + case remote(info: ItemCollectionInfo, items: [ItemCollectionItem], installed: Bool) +} + +public func requestStickerSet(account:Account, reference: StickerPackReference) -> Signal { + + let collectionId:ItemCollectionId? + let input:Api.InputStickerSet + + switch reference { + case let .name(name): + collectionId = nil + input = .inputStickerSetShortName(shortName: name) + case let .id(id, accessHash): + collectionId = ItemCollectionId(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: id) + input = .inputStickerSetID(id: id, accessHash: accessHash) + } + + let localSignal:(ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, Void> = { collectionId in + return account.postbox.modify { modifier -> (ItemCollectionInfo, [ItemCollectionItem])? in + return modifier.getItemCollectionInfoItems(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: collectionId) + } + } + + let remoteSignal = account.network.request(Api.functions.messages.getStickerSet(stickerset: input)) + |> mapError { _ -> RequestStickerSetError in + return .invalid + } + |> map { result -> RequestStickerSetResult in + var items: [ItemCollectionItem] = [] + let info:ItemCollectionInfo + let installed:Bool + switch result { + case let .stickerSet(set, packs, documents): + + info = set.info + + switch set { + case let .stickerSet(data): + installed = (data.flags & (1 << 0) != 0) + } + + var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] + for pack in packs { + switch pack { + case let .stickerPack(text, fileIds): + let key = ValueBoxKey(text).toMemoryBuffer() + for fileId in fileIds { + let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) + if indexKeysByFile[mediaId] == nil { + indexKeysByFile[mediaId] = [key] + } else { + indexKeysByFile[mediaId]!.append(key) + } + } + break + } + } + + for apiDocument in documents { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + let fileIndexKeys: [MemoryBuffer] + if let indexKeys = indexKeysByFile[id] { + fileIndexKeys = indexKeys + } else { + fileIndexKeys = [] + } + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys)) + } + } + break + } + return .remote(info: info, items: items, installed: installed) + } + + + if let collectionId = collectionId { + return localSignal(collectionId) |> mapError {_ in return .generic} |> mapToSignal { result -> Signal in + if let result = result { + return .single(.local(info: result.0, items: result.1)) + } else { + return remoteSignal + } + } + } else { + return remoteSignal + } + + +} + +public enum InstallStickerSetError { + case generic +} + +public enum InstallStickerSetResult { + case successful + case archived([CoveredStickerSet]) +} + +public final class CoveredStickerSet : Equatable { + let items:[StickerPackItem] + let info:StickerPackCollectionInfo + public init(info:StickerPackCollectionInfo, items:[StickerPackItem]) { + self.items = items + self.info = info + } + + public static func ==(lhs:CoveredStickerSet, rhs:CoveredStickerSet) -> Bool { + return lhs.items == rhs.items && lhs.info == rhs.info + } +} + +public func installStickerSetInteractively(account:Account, info: StickerPackCollectionInfo, items: [ItemCollectionItem]) -> Signal { + + return account.network.request(Api.functions.messages.installStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash), archived: .boolFalse)) |> mapError { _ -> InstallStickerSetError in + return .generic + } |> mapToSignal { result -> Signal in + let addResult:InstallStickerSetResult + switch result { + case .stickerSetInstallResultSuccess: + addResult = .successful + case let .stickerSetInstallResultArchive(sets: archived): + var coveredSets:[CoveredStickerSet] = [] + for archived in archived { + let apiDocuments:[Api.Document] + let apiSet:Api.StickerSet + switch archived { + case let .stickerSetCovered(set: set, cover: cover): + apiSet = set + apiDocuments = [cover] + case let .stickerSetMultiCovered(set: set, covers: covers): + apiSet = set + apiDocuments = covers + } + + let info:StickerPackCollectionInfo = apiSet.info + + var items:[StickerPackItem] = [] + for apiDocument in apiDocuments { + if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id { + items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: [])) + } + } + coveredSets.append(CoveredStickerSet(info: info, items: items)) + } + addResult = .archived(coveredSets) + } + + + return account.postbox.modify { modifier -> Void in + var collections = modifier.getCollectionsItems(namespace: info.id.namespace) + + var removableIndexes:[Int] = [] + for i in 0 ..< collections.count { + if collections[i].0 == info.id { + removableIndexes.append(i) + } + if case let .archived(sets) = addResult { + for set in sets { + if collections[i].0 == set.info.id { + removableIndexes.append(i) + } + } + } + } + + for index in removableIndexes.reversed() { + collections.remove(at: index) + } + + collections.insert((info.id, info, items), at: 0) + + modifier.replaceItemCollections(namespace: info.id.namespace, itemCollections: collections) + } |> map { _ in return addResult} |> mapError {_ in return .generic} + } +} + + +public func uninstallStickerSetInteractively(account:Account, info:StickerPackCollectionInfo) -> Signal { + return account.network.request(Api.functions.messages.uninstallStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) + |> mapError {_ in + + } + |> mapToSignal { result-> Signal in + switch result { + case .boolTrue: + return account.postbox.modify { modifier -> Void in + var collections = modifier.getCollectionsItems(namespace: info.id.namespace) + + for i in 0 ..< collections.count { + if collections[i].0 == info.id { + collections.remove(at: i) + break + } + } + + modifier.replaceItemCollections(namespace: info.id.namespace, itemCollections: collections) + } + case .boolFalse: + return .complete() + } + } +} + + diff --git a/TelegramCore/ToggleChannelSignatures.swift b/TelegramCore/ToggleChannelSignatures.swift new file mode 100644 index 0000000000..6adc735479 --- /dev/null +++ b/TelegramCore/ToggleChannelSignatures.swift @@ -0,0 +1,22 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac +#else + import Postbox + import SwiftSignalKit + import MtProtoKitDynamic +#endif + +public func toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal { + return account.postbox.modify { modifier -> Signal in + if let peer = modifier.getPeer(peerId) as? TelegramChannel, let inputChannel = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.toggleSignatures(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> retryRequest |> map { updates -> Void in + account.stateManager.addUpdates(updates) + } + } else { + return .complete() + } + } |> switchToLatest +}