From 2fc72861e27876d3e71f13708c555db447ef164a Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 15 Jan 2026 14:47:50 +0000 Subject: [PATCH 1/4] multiplatform/common: catch every exception at base64ToBitmap (#6576) Co-authored-by: shum --- .../kotlin/chat/simplex/common/platform/Images.desktop.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Images.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Images.desktop.kt index d0ba082adf..d3b8cdcb58 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Images.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Images.desktop.kt @@ -27,7 +27,7 @@ actual fun base64ToBitmap(base64ImageString: String): ImageBitmap { .removePrefix("data:image/jpg;base64,") return try { ImageIO.read(ByteArrayInputStream(Base64.getMimeDecoder().decode(imageString))).toComposeImageBitmap() - } catch (e: IOException) { + } catch (e: Throwable) { Log.e(TAG, "base64ToBitmap error: $e") errorBitmap() } From 8d1ca9917b3725d6b61346414dfd3b8dd56a29f2 Mon Sep 17 00:00:00 2001 From: sh <37271604+shumvgolove@users.noreply.github.com> Date: Wed, 21 Jan 2026 09:14:04 +0000 Subject: [PATCH 2/4] multiplatform: stop video playback when swiping away (#6588) * android/build.gralde.kts: add JAVA_HOME to PATH * fullScreenView: dispose player.stop when view changes * fullScreenView: stop the video playback midway swipe Previously, video playback stopped **only** when screen was fully swiped away to next item. * ImageFullScreenView: simplify * revert back VideoView --- apps/multiplatform/android/build.gradle.kts | 5 ++++- .../simplex/common/views/chat/item/ImageFullScreenView.kt | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/multiplatform/android/build.gradle.kts b/apps/multiplatform/android/build.gradle.kts index 9b4e7ad58c..ae608c8c1d 100644 --- a/apps/multiplatform/android/build.gradle.kts +++ b/apps/multiplatform/android/build.gradle.kts @@ -192,7 +192,10 @@ tasks { } exec { workingDir("../../scripts/android") - environment = mapOf("JAVA_HOME" to "$javaHome") + environment = mapOf( + "JAVA_HOME" to "$javaHome", + "PATH" to "${javaHome}/bin${File.pathSeparator}${System.getenv("PATH")}" + ) commandLine = listOf( "./compress-and-sign-apk.sh", "${rootProject.extra["compression.level"]}", diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt index 70d6fa4aa8..8d96102daa 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt @@ -158,7 +158,10 @@ fun ImageFullScreenView(imageProvider: () -> ImageGalleryProvider, close: () -> val uriDecrypted = remember(media.uri.path) { mutableStateOf(if (media.fileSource?.cryptoArgs == null) media.uri else media.fileSource.decryptedGet()) } val decrypted = uriDecrypted.value if (decrypted != null) { - VideoView(modifier, decrypted, preview, index == settledCurrentPage, close) + // settledCurrentPage finishes **only** when fully swiped + // So we use pagerState.currentPage that changes right away as the screen is being dragged + val isCurrentPage = index == pagerState.currentPage && kotlin.math.abs(pagerState.currentPageOffsetFraction) < 0.3f + VideoView(modifier, decrypted, preview, isCurrentPage, close) DisposableEffect(Unit) { onDispose { playersToRelease.add(decrypted) } } From a786693c1a2c0ef29e199594fb4f21821fc2b48b Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 28 Jan 2026 21:57:39 +0000 Subject: [PATCH 3/4] core: improve error handling (#6602) * core: improve error handling * simplexmq --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- src/Simplex/Chat/Library/Commands.hs | 4 ++-- src/Simplex/Chat/Library/Internal.hs | 10 +++++----- src/Simplex/Chat/Protocol.hs | 26 ++++++++++++++++---------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cabal.project b/cabal.project index aee9490aef..f2a4f74093 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 2ea98db9d8ad0dc43820227a89c744822dfadb5d + tag: 3c5ec8d9a185e3decd8a52912022c9ec5f2a7730 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 9eed446658..e343686d53 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."2ea98db9d8ad0dc43820227a89c744822dfadb5d" = "1vh9s66yywqi33df0la340jws9z3hag7ym7q03rc9x8cjcg6s8sw"; + "https://github.com/simplex-chat/simplexmq.git"."3c5ec8d9a185e3decd8a52912022c9ec5f2a7730" = "0dlg8dw9isdazxjarzz87p80wbsjyg7ivrqs7dvapp6s58ai8i8f"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index b668a1d793..f193ab43a9 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -4126,7 +4126,7 @@ agentSubscriber :: CM' () agentSubscriber = do q <- asks $ subQ . smpAgent forever (atomically (readTBQueue q) >>= process) - `E.catchAny` \e -> do + `catchOwn` \e -> do eToView' $ ChatErrorAgent (CRITICAL True $ "Message reception stopped: " <> show e) Nothing E.throwIO e where @@ -4137,7 +4137,7 @@ agentSubscriber = do SAERcvFile -> processAgentMsgRcvFile corrId entId msg SAESndFile -> processAgentMsgSndFile corrId entId msg where - run action = action `catchAllErrors'` (eToView') + run action = action `catchAllOwnErrors'` eToView' type AgentBatchSubscribe = AgentClient -> [ConnId] -> ExceptT AgentErrorType IO (Map ConnId (Either AgentErrorType (Maybe ClientServiceId))) diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index e3885a3c9a..34a72ba66f 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -563,7 +563,6 @@ markGroupCIsDeleted user gInfo chatScopeInfo items byGroupMember_ deletedTs = do (errs, deletions) <- lift $ partitionEithers <$> withStoreBatch' (\db -> map (markDeleted db) items) unless (null errs) $ toView $ CEvtChatErrors errs pure deletions - -- pure $ CRChatItemsDeleted user deletions byUser False where markDeleted db (CChatItem md ci) = do ci' <- markGroupChatItemDeleted db user gInfo ci byGroupMember_ deletedTs @@ -2115,7 +2114,7 @@ saveSndChatItems user cd itemsData itemTimed live = do createdAt <- liftIO getCurrentTime vr <- chatVersionRange when (contactChatDeleted cd || any (\NewSndChatItemData {content} -> ciRequiresAttention content) (rights itemsData)) $ - void $ withStore' (\db -> updateChatTsStats db vr user cd createdAt Nothing) + void (withStore' $ \db -> updateChatTsStats db vr user cd createdAt Nothing) lift $ withStoreBatch (\db -> map (bindRight $ createItem db createdAt) itemsData) where createItem :: DB.Connection -> UTCTime -> NewSndChatItemData c -> IO (Either ChatError (ChatItem c 'MDSnd)) @@ -2151,9 +2150,10 @@ saveRcvChatItem' user cd msg@RcvMessage {chatMsgEvent, forwardedByMember} shared userMention' = userReply || any (\CIMention {memberId} -> sameMemberId memberId membership) mentions' in pure (mentions', userMention') CDDirectRcv _ -> pure (M.empty, False) - cInfo' <- if (ciRequiresAttention content || contactChatDeleted cd) - then updateChatTsStats db vr user cd createdAt (memberChatStats userMention) - else pure $ toChatInfo cd + cInfo' <- + if ciRequiresAttention content || contactChatDeleted cd + then updateChatTsStats db vr user cd createdAt (memberChatStats userMention) + else pure $ toChatInfo cd (ciId, quotedItem, itemForwarded) <- createNewRcvChatItem db user cd msg sharedMsgId_ content itemTimed live userMention brokerTs createdAt forM_ ciFile $ \CIFile {fileId} -> updateFileTransferChatItemId db fileId ciId createdAt let ci = mkChatItem_ cd False ciId content (t, ft_) ciFile quotedItem sharedMsgId_ itemForwarded itemTimed live userMention brokerTs forwardedByMember createdAt diff --git a/src/Simplex/Chat/Protocol.hs b/src/Simplex/Chat/Protocol.hs index d6b826491e..aecf376e27 100644 --- a/src/Simplex/Chat/Protocol.hs +++ b/src/Simplex/Chat/Protocol.hs @@ -234,8 +234,7 @@ instance StrEncoding AppMessageBinary where let msgId = if B.null msgId' then Nothing else Just (SharedMsgId msgId') pure AppMessageBinary {tag, msgId, body} -data MsgScope - = MSMember {memberId :: MemberId} -- Admins can use any member id; members can use only their own id +data MsgScope = MSMember {memberId :: MemberId} -- Admins can use any member id; members can use only their own id deriving (Eq, Show) $(JQ.deriveJSON (taggedObjectJSON $ dropPrefix "MS") ''MsgScope) @@ -673,6 +672,9 @@ maxEncodedMsgLength = 15602 maxCompressedMsgLength :: Int maxCompressedMsgLength = 13380 +maxDecompressedMsgLength :: Int +maxDecompressedMsgLength = 65536 + -- maxEncodedMsgLength - delta between MSG and INFO + 100 (returned for forward overhead) -- delta between MSG and INFO = e2eEncUserMsgLength (no PQ) - e2eEncConnInfoLength (no PQ) = 1008 maxEncodedInfoLength :: Int @@ -695,20 +697,24 @@ encodeChatMessage maxSize msg = do parseChatMessages :: ByteString -> [Either String AChatMessage] parseChatMessages "" = [Left "empty string"] -parseChatMessages s = case B.head s of - '{' -> [ACMsg SJson <$> J.eitherDecodeStrict' s] - '[' -> case J.eitherDecodeStrict' s of - Right v -> map parseItem v - Left e -> [Left e] - 'X' -> decodeCompressed (B.drop 1 s) - _ -> [ACMsg SBinary <$> (appBinaryToCM =<< strDecode s)] +parseChatMessages msg = case B.head msg of + 'X' -> decodeCompressed (B.tail msg) + c -> parseUncompressed c msg where + parseUncompressed c s = case c of + '{' -> [ACMsg SJson <$> J.eitherDecodeStrict' s] + '[' -> case J.eitherDecodeStrict' s of + Right v -> map parseItem v + Left e -> [Left e] + _ -> [ACMsg SBinary <$> (appBinaryToCM =<< strDecode s)] parseItem :: J.Value -> Either String AChatMessage parseItem v = ACMsg SJson <$> JT.parseEither parseJSON v decodeCompressed :: ByteString -> [Either String AChatMessage] decodeCompressed s' = case smpDecode s' of Left e -> [Left e] - Right (compressed :: L.NonEmpty Compressed) -> concatMap (either (pure . Left) parseChatMessages . decompress1) compressed + Right (compressed :: L.NonEmpty Compressed) -> concatMap (either (pure . Left) parseUncompressed' . decompress1 maxDecompressedMsgLength) compressed + parseUncompressed' "" = [Left "empty string"] + parseUncompressed' s = parseUncompressed (B.head s) s compressedBatchMsgBody_ :: MsgBody -> ByteString compressedBatchMsgBody_ = markCompressedBatch . smpEncode . (L.:| []) . compress1 From 5d32e14559ab18d61d6e8da1c4e070ffd87d54b2 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Wed, 28 Jan 2026 22:03:25 +0000 Subject: [PATCH 4/4] core: 6.4.10.0 (simplexmq 6.4.8.0) --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cabal.project b/cabal.project index f2a4f74093..3242d9ca49 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 3c5ec8d9a185e3decd8a52912022c9ec5f2a7730 + tag: 9346b85c3f34f8b12fefef4631ba21087cf5f0e3 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index e343686d53..acb6a31426 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."3c5ec8d9a185e3decd8a52912022c9ec5f2a7730" = "0dlg8dw9isdazxjarzz87p80wbsjyg7ivrqs7dvapp6s58ai8i8f"; + "https://github.com/simplex-chat/simplexmq.git"."9346b85c3f34f8b12fefef4631ba21087cf5f0e3" = "010xj64rwj4g36f42znjv73c4armsdm6q9rdpxy1bqknwcbsk2sw"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 986562a5e9..dbee10706c 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 6.4.9.0 +version: 6.4.10.0 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat