Fix delete-message handler: call deleteIMMessageItems: instead of deleteChatItems: - #55
Draft
ardydavari wants to merge 1 commit into
Draft
Conversation
…teChatItems:
The delete-message action was calling -[IMChat deleteChatItems:] with an
array of IMMessagePartChatItem (the message's parts — text ranges, attachment
slots). On macOS 26 Tahoe this invokes IMCore's "delete subset of chat items
from message → update message" path, which logs:
(IMCore) [ChatItems] Processing 1 chat items for deletion
(IMCore) [ChatItems] Request to delete subset of chatItems from message.
Update message.
(IMCore) [ChatItems] DELETING PARTS index:range map: <private>
…but the message row stays in chat_message_join and no entry is written to
sync_deleted_messages, so the delete never propagates to other devices via
iCloud. The HTTP API returns {"status":200,"message":"Successfully deleted
message!"} because the transaction ACK fires outside the completion block,
masking the silent no-op.
The correct method is -[IMChat deleteIMMessageItems:], which takes an array
of IMMessageItem (whole messages) and hits the real delete path: the row is
removed from chat_message_join, an entry is added to sync_deleted_messages
with a CloudKit recordID, and the delete propagates across all devices
signed into Messages-in-iCloud.
Both methods are declared in the existing IMChat.h headers for MacOS-10 and
MacOS-11+, so no new imports are needed.
Verified end-to-end on macOS 26.4 Tahoe by:
1. Rebuilding the MacOS-11+ helper dylib with this fix.
2. Deploying to /Applications/BlueBubbles.app/.../BlueBubblesHelper.dylib.
3. Deleting 95 messages from 1:1 and group chats via apply.py / bulk curl.
4. Confirming each message was removed from message and
chat_message_join on the issuing device, added to sync_deleted_messages
with a valid CloudKit recordID, and propagated to
chat_recoverable_message_join on the user's main Mac via iCloud.
The same fix is applied to both MacOS-10 and MacOS-11+ copies of the
helper source since both have identical incorrect code.
Member
|
macOS version coverage should be fine if the API is present in both version header dumbs. The second bullet which you mentioned - we would want to check what the native iMessage behavior is. Does the iMessage app support deleting specific parts of a "multipart" message? E.g. receiving multiple attachments + text in a single message, can you delete out a single attachment? I would presume so, but haven't had the chance to check. If so, we need to find a better way to do this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
delete-messageaction inBlueBubblesHelper.mcalls-[IMChat deleteChatItems:]with an array ofIMMessagePartChatItem(message parts — text ranges, attachment slots). This hits IMCore's "delete subset of chat items from message → update message" code path, which logs activity that looks like a delete is happening:…but the message row stays in
chat_message_join, no entry is written tosync_deleted_messages, and nothing propagates via iCloud. Meanwhile, the HTTP API returns{\"status\":200,\"message\":\"Successfully deleted message!\"}because the transaction ACK in the helper fires outside thegetMessageItem:completionBlock:callback, so the server never sees the no-op.The correct method for whole-message delete is
-[IMChat deleteIMMessageItems:], which takes an array ofIMMessageItemand invokes IMCore's real delete path — row removal,sync_deleted_messagesentry with a CloudKitrecordID, and iCloud propagation to all signed-in devices.Both methods are already declared in the existing
IMChat.hheaders for MacOS-10 and MacOS-11+, so no new imports are required.The fix
} else if ([event isEqualToString:@\"delete-message\"]) { IMChat *chat = [BlueBubblesHelper getChat: data[@\"chatGuid\"] :transaction]; if (chat != nil) { [BlueBubblesHelper getMessageItem:(chat) :(data[@\"messageGuid\"]) completionBlock:^(IMMessage *message) { IMMessageItem *messageItem = (IMMessageItem *)message._imMessageItem; - NSObject *items = messageItem._newChatItems; - IMMessagePartChatItem *item; - if ([items isKindOfClass:[NSArray class]]) { - [chat deleteChatItems:(items)]; - } else { - [chat deleteChatItems:(@[items])]; + if (messageItem != nil) { + [chat deleteIMMessageItems:@[messageItem]]; } }]; ... } }Applied to both
Messages/MacOS-10/BlueBubblesHelper/BlueBubblesHelper.mandMessages/MacOS-11+/BlueBubblesHelper/BlueBubblesHelper.msince both copies had identical incorrect code.Diagnostic notes
Caught with `log stream --predicate 'process == "Messages"' --level debug` on macOS 26.4 Tahoe while firing
DELETE /api/v1/chat/:guid/:messageGuid. The IMCore logs above made it clear the call was going down the part-delete path; cross-referencingIMChat.hin this repo showeddeleteIMMessageItems:sitting right next todeleteChatItems:at lines 376-377, confirming the correct method exists.One subtlety that masks the bug: the helper sends the transaction ACK immediately after kicking off
getMessageItem:completionBlock:, not from inside the completion block. So even if the IMCore call was silently throwing or hanging, the server would still see success. Worth being aware of when debugging other actions.Verification
Verified end-to-end on macOS 26.4 Tahoe (Messages.app 26.0, IMCore 800.0.0):
clang -dynamiclibdirectly against the SDK's private frameworks (no Xcode required, just Command Line Tools)./Applications/BlueBubbles.app/Contents/Resources/appResources/private-api/macos11/BlueBubblesHelper.dylib.lsof -p <messages_pid> | grep BlueBubbles.messagerow was removed from the table on the issuing devicesync_deleted_messageshad an entry with a valid CloudKit recordIDchat_recoverable_message_joinwithin secondsNot verified
deleteIMMessageItems:selector is present in this repo's class-dumpedIMChat.hfor both MacOS-10 and MacOS-11+, so it should be available, but I haven't tested outside Tahoe. A quick sanity check from a maintainer on an earlier macOS would be helpful before merging.send-multipartedge case where_newChatItemsmight have been relevant. I replaced the_newChatItemsaccess entirely, so if there's a scenario where the helper legitimately needs to delete a subset of parts (e.g., removing an attachment while keeping text), this fix is too aggressive. I couldn't find such a call site in the BlueBubbles server, but if one exists, the fix may need to gate on whether the caller wants whole-message or part-level delete.Opening as a draft so maintainers can weigh in on macOS-version coverage before landing.