diff --git a/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift b/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift index 020ae7aa7c..eead72c488 100644 --- a/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift +++ b/submodules/ChatImportUI/Sources/ChatImportActivityScreen.swift @@ -65,7 +65,7 @@ private final class ImportManager { } private let account: Account - private let archivePath: String + private let archivePath: String? private let entries: [(SSZipEntry, String, ChatHistoryImport.MediaType)] private var session: ChatHistoryImport.Session? @@ -89,7 +89,7 @@ private final class ImportManager { return self.statePromise.get() } - init(account: Account, peerId: PeerId, mainFile: TempBoxFile, archivePath: String, entries: [(SSZipEntry, String, ChatHistoryImport.MediaType)]) { + init(account: Account, peerId: PeerId, mainFile: TempBoxFile, archivePath: String?, entries: [(SSZipEntry, String, ChatHistoryImport.MediaType)]) { self.account = account self.archivePath = archivePath self.entries = entries @@ -187,70 +187,81 @@ private final class ImportManager { guard let session = self.session else { return } - if self.activeEntries.count >= 3 { - return - } - if self.pendingEntries.isEmpty { + if self.pendingEntries.isEmpty && self.activeEntries.isEmpty { self.complete() return } if case .error = self.stateValue { return } + guard let archivePath = self.archivePath else { + return + } - let entry = self.pendingEntries.removeFirst() - let archivePath = self.archivePath - let unpackedFile = Signal { subscriber in - let tempFile = TempBox.shared.tempFile(fileName: entry.0.path) - print("Extracting \(entry.0.path) to \(tempFile.path)...") - let startTime = CACurrentMediaTime() - if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.0.path, toPath: tempFile.path) { - print("[Done in \(CACurrentMediaTime() - startTime) s] Extract \(entry.0.path) to \(tempFile.path)") - subscriber.putNext(tempFile) - subscriber.putCompletion() - } else { - subscriber.putError(.generic) + while true { + if self.activeEntries.count >= 3 { + break + } + if self.pendingEntries.isEmpty { + break } - return EmptyDisposable - } - - let account = self.account - - let uploadedEntrySignal: Signal = unpackedFile - |> mapToSignal { tempFile -> Signal in - return ChatHistoryImport.uploadMedia(account: account, session: session, file: tempFile, fileName: entry.0.path, mimeType: entry.1, type: entry.2) - |> mapError { error -> ImportError in - switch error { - case .chatAdminRequired: - return .chatAdminRequired - case .generic: - return .generic + let entry = self.pendingEntries.removeFirst() + let unpackedFile = Signal { subscriber in + let tempFile = TempBox.shared.tempFile(fileName: entry.0.path) + Logger.shared.log("ChatImportScreen", "Extracting \(entry.0.path) to \(tempFile.path)...") + let startTime = CACurrentMediaTime() + if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.0.path, toPath: tempFile.path) { + Logger.shared.log("ChatImportScreen", "[Done in \(CACurrentMediaTime() - startTime) s] Extract \(entry.0.path) to \(tempFile.path)") + subscriber.putNext(tempFile) + subscriber.putCompletion() + } else { + subscriber.putError(.generic) + } + + return EmptyDisposable + } + + let account = self.account + + let uploadedEntrySignal: Signal = unpackedFile + |> mapToSignal { tempFile -> Signal in + return ChatHistoryImport.uploadMedia(account: account, session: session, file: tempFile, fileName: entry.0.path, mimeType: entry.1, type: entry.2) + |> mapError { error -> ImportError in + switch error { + case .chatAdminRequired: + return .chatAdminRequired + case .generic: + return .generic + } } } + + let disposable = MetaDisposable() + self.activeEntries[entry.1] = disposable + + disposable.set((uploadedEntrySignal + |> deliverOnMainQueue).start(next: { [weak self] progress in + guard let strongSelf = self else { + return + } + if let (size, _) = strongSelf.entryProgress[entry.0.path] { + strongSelf.entryProgress[entry.0.path] = (size, Int(progress * Float(entry.0.uncompressedSize))) + strongSelf.updateProgress() + } + }, error: { [weak self] error in + guard let strongSelf = self else { + return + } + strongSelf.failWithError(error) + }, completed: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.activeEntries.removeValue(forKey: entry.0.path) + strongSelf.updateState() + })) } - - self.activeEntries[entry.1] = (uploadedEntrySignal - |> deliverOnMainQueue).start(next: { [weak self] progress in - guard let strongSelf = self else { - return - } - if let (size, _) = strongSelf.entryProgress[entry.0.path] { - strongSelf.entryProgress[entry.0.path] = (size, Int(progress * Float(entry.0.uncompressedSize))) - strongSelf.updateProgress() - } - }, error: { [weak self] error in - guard let strongSelf = self else { - return - } - strongSelf.failWithError(error) - }, completed: { [weak self] in - guard let strongSelf = self else { - return - } - strongSelf.activeEntries.removeValue(forKey: entry.0.path) - strongSelf.updateState() - }) } } @@ -652,7 +663,7 @@ public final class ChatImportActivityScreen: ViewController { private var presentationData: PresentationData fileprivate let cancel: () -> Void fileprivate var peerId: PeerId - private let archivePath: String + private let archivePath: String? private let mainEntry: TempBoxFile private let totalBytes: Int private let totalMediaBytes: Int @@ -673,7 +684,7 @@ public final class ChatImportActivityScreen: ViewController { } } - public init(context: AccountContext, cancel: @escaping () -> Void, peerId: PeerId, archivePath: String, mainEntry: TempBoxFile, otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType)]) { + public init(context: AccountContext, cancel: @escaping () -> Void, peerId: PeerId, archivePath: String?, mainEntry: TempBoxFile, otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType)]) { self.context = context self.cancel = cancel self.peerId = peerId @@ -769,10 +780,8 @@ public final class ChatImportActivityScreen: ViewController { } strongSelf.controllerNode.updateState(state: state, animated: true) if case let .progress(_, _, totalMediaBytes, totalUploadedMediaBytes) = state { - if let progressEstimator = strongSelf.progressEstimator { - let progress = Float(totalUploadedMediaBytes) / Float(totalMediaBytes) - strongSelf.totalMediaProgress = progress - } + let progress = Float(totalUploadedMediaBytes) / Float(totalMediaBytes) + strongSelf.totalMediaProgress = progress } })) }, error: { [weak self] error in diff --git a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTGzip.h b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTGzip.h index 3c255592ba..fe16814ea6 100644 --- a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTGzip.h +++ b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTGzip.h @@ -5,6 +5,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MTGzip : NSObject + (NSData * _Nullable)decompress:(NSData *)data; ++ (NSData * _Nullable)compress:(NSData *)data; @end diff --git a/submodules/MtProtoKit/Sources/MTGzip.m b/submodules/MtProtoKit/Sources/MTGzip.m index fa7f1ba182..c529dbad29 100644 --- a/submodules/MtProtoKit/Sources/MTGzip.m +++ b/submodules/MtProtoKit/Sources/MTGzip.m @@ -50,4 +50,42 @@ return (retCode == Z_STREAM_END ? result : nil); } ++ (NSData * _Nullable)compress:(NSData *)data { + if (data.length == 0) { + return data; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = (uint)data.length; + stream.next_in = (Bytef *)(void *)data.bytes; + stream.total_out = 0; + stream.avail_out = 0; + + static const NSUInteger ChunkSize = 16384; + + NSMutableData *output = nil; + int compression = Z_BEST_COMPRESSION; + if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) + { + output = [NSMutableData dataWithLength:ChunkSize]; + while (stream.avail_out == 0) + { + if (stream.total_out >= output.length) + { + output.length += ChunkSize; + } + stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(output.length - stream.total_out); + deflate(&stream, Z_FINISH); + } + deflateEnd(&stream); + output.length = stream.total_out; + } + + return output; +} + @end diff --git a/submodules/TelegramCore/Sources/ChatHistoryImport.swift b/submodules/TelegramCore/Sources/ChatHistoryImport.swift index e202b53bc6..971e63ca83 100644 --- a/submodules/TelegramCore/Sources/ChatHistoryImport.swift +++ b/submodules/TelegramCore/Sources/ChatHistoryImport.swift @@ -49,7 +49,7 @@ public enum ChatHistoryImport { } public static func initSession(account: Account, peerId: PeerId, file: TempBoxFile, mediaCount: Int32) -> Signal { - return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false) + return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false, useLargerParts: true, increaseParallelParts: true, useMultiplexedRequests: false, useCompression: true) |> mapError { _ -> InitImportError in return .generic } diff --git a/submodules/TelegramCore/Sources/Download.swift b/submodules/TelegramCore/Sources/Download.swift index 00d4108fd2..4220b040c9 100644 --- a/submodules/TelegramCore/Sources/Download.swift +++ b/submodules/TelegramCore/Sources/Download.swift @@ -22,6 +22,20 @@ enum UploadPartError { case invalidMedia } +private func wrapMethodBody(_ body: (FunctionDescription, Buffer, DeserializeFunctionResponse), useCompression: Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + if useCompression { + if let compressed = MTGzip.compress(body.1.makeData()) { + if compressed.count < body.1.size { + let os = MTOutputStream() + os.write(0x3072cfa1 as Int32) + os.writeBytes(compressed) + return (body.0, Buffer(data: os.currentBytes()), body.2) + } + } + } + + return body +} class Download: NSObject, MTRequestMessageServiceDelegate { let datacenterId: Int @@ -82,7 +96,7 @@ class Download: NSObject, MTRequestMessageServiceDelegate { self.context.authTokenForDatacenter(withIdRequired: self.datacenterId, authToken:self.mtProto.requiredAuthToken, masterDatacenterId: self.mtProto.authTokenMasterDatacenterId) } - static func uploadPart(multiplexedManager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64, tag: MediaResourceFetchTag?, fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal { + static func uploadPart(multiplexedManager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64, tag: MediaResourceFetchTag?, fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil, useCompression: Bool = false) -> Signal { let saveFilePart: (FunctionDescription, Buffer, DeserializeFunctionResponse) if asBigPart { let totalParts: Int32 @@ -96,7 +110,7 @@ class Download: NSObject, MTRequestMessageServiceDelegate { saveFilePart = Api.functions.upload.saveFilePart(fileId: fileId, filePart: Int32(index), bytes: Buffer(data: data)) } - return multiplexedManager.request(to: .main(datacenterId), consumerId: consumerId, data: saveFilePart, tag: tag, continueInBackground: true) + return multiplexedManager.request(to: .main(datacenterId), consumerId: consumerId, data: wrapMethodBody(saveFilePart, useCompression: useCompression), tag: tag, continueInBackground: true) |> mapError { error -> UploadPartError in if error.errorCode == 400 { return .invalidMedia @@ -109,11 +123,11 @@ class Download: NSObject, MTRequestMessageServiceDelegate { } } - func uploadPart(fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal { + func uploadPart(fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil, useCompression: Bool = false) -> Signal { return Signal { subscriber in let request = MTRequest() - let saveFilePart: (FunctionDescription, Buffer, DeserializeFunctionResponse) + var saveFilePart: (FunctionDescription, Buffer, DeserializeFunctionResponse) if asBigPart { let totalParts: Int32 if let bigTotalParts = bigTotalParts { @@ -126,6 +140,8 @@ class Download: NSObject, MTRequestMessageServiceDelegate { saveFilePart = Api.functions.upload.saveFilePart(fileId: fileId, filePart: Int32(index), bytes: Buffer(data: data)) } + saveFilePart = wrapMethodBody(saveFilePart, useCompression: useCompression) + request.setPayload(saveFilePart.1.makeData() as Data, metadata: WrappedRequestMetadata(metadata: WrappedFunctionDescription(saveFilePart.0), tag: nil), shortMetadata: WrappedRequestShortMetadata(shortMetadata: WrappedShortFunctionDescription(saveFilePart.0)), responseParser: { response in if let result = saveFilePart.2.parse(Buffer(data: response)) { return BoxedMessage(result) diff --git a/submodules/TelegramCore/Sources/MultipartUpload.swift b/submodules/TelegramCore/Sources/MultipartUpload.swift index 1c094691ac..0736fd4940 100644 --- a/submodules/TelegramCore/Sources/MultipartUpload.swift +++ b/submodules/TelegramCore/Sources/MultipartUpload.swift @@ -113,7 +113,7 @@ private enum HeaderPartState { } private final class MultipartUploadManager { - let parallelParts: Int = 3 + let parallelParts: Int var defaultPartSize: Int var bigTotalParts: Int? var bigParts: Bool @@ -140,13 +140,19 @@ private final class MultipartUploadManager { let state: MultipartUploadState - init(headerSize: Int32, data: Signal, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool, uploadPart: @escaping (UploadPart) -> Signal, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) { + init(headerSize: Int32, data: Signal, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool, increaseParallelParts: Bool, uploadPart: @escaping (UploadPart) -> Signal, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) { self.dataSignal = data var fileId: Int64 = 0 arc4random_buf(&fileId, 8) self.fileId = fileId + if increaseParallelParts { + self.parallelParts = 30 + } else { + self.parallelParts = 3 + } + self.forceNoBigParts = forceNoBigParts self.useLargerParts = useLargerParts @@ -381,7 +387,7 @@ enum MultipartUploadError { case generic } -func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool = false, useMultiplexedRequests: Bool = false) -> Signal { +func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool, forceNoBigParts: Bool, useLargerParts: Bool = false, increaseParallelParts: Bool = false, useMultiplexedRequests: Bool = false, useCompression: Bool = false) -> Signal { enum UploadInterface { case download(Download) case multiplexed(manager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64) @@ -447,12 +453,12 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload fetchedResource = .complete() } - let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: forceNoBigParts, useLargerParts: useLargerParts, uploadPart: { part in + let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, forceNoBigParts: forceNoBigParts, useLargerParts: useLargerParts, increaseParallelParts: increaseParallelParts, uploadPart: { part in switch uploadInterface { case let .download(download): - return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts) + return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts, useCompression: useCompression) case let .multiplexed(multiplexed, datacenterId, consumerId): - return Download.uploadPart(multiplexedManager: multiplexed, datacenterId: datacenterId, consumerId: consumerId, tag: nil, fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts) + return Download.uploadPart(multiplexedManager: multiplexed, datacenterId: datacenterId, consumerId: consumerId, tag: nil, fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts, useCompression: useCompression) } }, progress: { progress in subscriber.putNext(.progress(progress)) diff --git a/submodules/TelegramUI/Sources/ShareExtensionContext.swift b/submodules/TelegramUI/Sources/ShareExtensionContext.swift index 8b43cca864..4846204af6 100644 --- a/submodules/TelegramUI/Sources/ShareExtensionContext.swift +++ b/submodules/TelegramUI/Sources/ShareExtensionContext.swift @@ -401,81 +401,98 @@ public class ShareRootControllerImpl { return } let fileExtension = (fileName as NSString).pathExtension - guard fileExtension.lowercased() == "zip" else { - beginShare() - return - } - - let archivePath = url.path - - guard let entries = SSZipArchive.getEntriesForFile(atPath: archivePath) else { - beginShare() - return - } - - let mainFileNames: [NSRegularExpression] = [ - try! NSRegularExpression(pattern: "_chat\\.txt"), - try! NSRegularExpression(pattern: "KakaoTalkChats\\.txt"), - try! NSRegularExpression(pattern: "Talk_.*?\\.txt"), - ] - - var maybeMainFileName: String? - mainFileLoop: for entry in entries { - let entryFileName = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_") - let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName) - for expression in mainFileNames { - if expression.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { - maybeMainFileName = entryFileName - break mainFileLoop - } - } - } - - guard let mainFileName = maybeMainFileName else { - beginShare() - return - } - - let photoRegex = try! NSRegularExpression(pattern: ".*?\\.jpg") - let videoRegex = try! NSRegularExpression(pattern: "[\\d]+-VIDEO-.*?\\.mp4") - let stickerRegex = try! NSRegularExpression(pattern: "[\\d]+-STICKER-.*?\\.webp") - let voiceRegex = try! NSRegularExpression(pattern: "[\\d]+-AUDIO-.*?\\.opus") + var archivePathValue: String? var otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType)] = [] - var mainFile: TempBoxFile? - do { - for entry in entries { - let entryPath = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_") - if entryPath.isEmpty { - continue - } - let tempFile = TempBox.shared.tempFile(fileName: entryPath) - if entryPath == mainFileName { - if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.path, toPath: tempFile.path) { - mainFile = tempFile - } - } else { - let entryFileName = (entryPath as NSString).lastPathComponent - if !entryFileName.isEmpty { - let mediaType: ChatHistoryImport.MediaType - let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName) - if photoRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { - mediaType = .photo - } else if videoRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { - mediaType = .video - } else if stickerRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { - mediaType = .sticker - } else if voiceRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { - mediaType = .voice - } else { - mediaType = .file - } - otherEntries.append((entry, entryFileName, mediaType)) + + if fileExtension.lowercased() == "zip" { + let archivePath = url.path + archivePathValue = archivePath + + guard let entries = SSZipArchive.getEntriesForFile(atPath: archivePath) else { + beginShare() + return + } + + let mainFileNames: [NSRegularExpression] = [ + try! NSRegularExpression(pattern: "_chat\\.txt"), + try! NSRegularExpression(pattern: "KakaoTalkChats\\.txt"), + try! NSRegularExpression(pattern: "Talk_.*?\\.txt"), + ] + + var maybeMainFileName: String? + mainFileLoop: for entry in entries { + let entryFileName = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_") + let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName) + for expression in mainFileNames { + if expression.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { + maybeMainFileName = entryFileName + break mainFileLoop } } } - } catch { + + guard let mainFileName = maybeMainFileName else { + beginShare() + return + } + + let photoRegex = try! NSRegularExpression(pattern: ".*?\\.jpg") + let videoRegex = try! NSRegularExpression(pattern: "[\\d]+-VIDEO-.*?\\.mp4") + let stickerRegex = try! NSRegularExpression(pattern: "[\\d]+-STICKER-.*?\\.webp") + let voiceRegex = try! NSRegularExpression(pattern: "[\\d]+-AUDIO-.*?\\.opus") + + do { + for entry in entries { + let entryPath = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_") + if entryPath.isEmpty { + continue + } + let tempFile = TempBox.shared.tempFile(fileName: entryPath) + if entryPath == mainFileName { + if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.path, toPath: tempFile.path) { + mainFile = tempFile + } + } else { + let entryFileName = (entryPath as NSString).lastPathComponent + if !entryFileName.isEmpty { + let mediaType: ChatHistoryImport.MediaType + let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName) + if photoRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { + mediaType = .photo + } else if videoRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { + mediaType = .video + } else if stickerRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { + mediaType = .sticker + } else if voiceRegex.firstMatch(in: entryFileName, options: [], range: fullRange) != nil { + mediaType = .voice + } else { + mediaType = .file + } + otherEntries.append((entry, entryFileName, mediaType)) + } + } + } + } + } else if fileExtension.lowercased() == "txt" { + if let mainFileText = try? String(contentsOf: URL(fileURLWithPath: url.path)) { + if !mainFileText.hasPrefix("[LINE]") { + beginShare() + return + } + } else { + beginShare() + return + } + + let tempFile = TempBox.shared.tempFile(fileName: "History.txt") + if let _ = try? FileManager.default.copyItem(atPath: url.path, toPath: tempFile.path) { + mainFile = tempFile + } else { + beginShare() + return + } } if let mainFile = mainFile, let mainFileText = try? String(contentsOf: URL(fileURLWithPath: mainFile.path)) { @@ -561,7 +578,7 @@ public class ShareRootControllerImpl { navigationController.view.endEditing(true) navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: { self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) - }, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries)) + }, peerId: peerId, archivePath: archivePathValue, mainEntry: mainFile, otherEntries: otherEntries)) } attemptSelectionImpl = { peer in @@ -675,7 +692,7 @@ public class ShareRootControllerImpl { navigationController.view.endEditing(true) navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: { self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) - }, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries)) + }, peerId: peerId, archivePath: archivePathValue, mainEntry: mainFile, otherEntries: otherEntries)) } attemptSelectionImpl = { [weak controller] peer in @@ -737,7 +754,7 @@ public class ShareRootControllerImpl { navigationController.view.endEditing(true) navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: { self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) - }, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries)) + }, peerId: peerId, archivePath: archivePathValue, mainEntry: mainFile, otherEntries: otherEntries)) } attemptSelectionImpl = { [weak controller] peer in