[GH-ISSUE #16] Add support for iMessage replies #18

Open
opened 2026-03-02 23:33:00 +03:00 by kerem · 2 comments
Owner

Originally created by @Hoodgail on GitHub (Jul 3, 2022).
Original GitHub issue: https://github.com/airmessage/airmessage-server/issues/16

Do you see how imessage shows what message is being replied to?
image
Will there be such features for airmessage? doesnt need to have the same interface as imessage
image (5)
It could even look something simple like discord's

And later on add to support to reply from airmessage.
maybe a context menu on right click with the reply button.

Originally created by @Hoodgail on GitHub (Jul 3, 2022). Original GitHub issue: https://github.com/airmessage/airmessage-server/issues/16 Do you see how imessage shows what message is being replied to? ![image](https://user-images.githubusercontent.com/45743294/177019507-db6271eb-9219-474d-acf2-ffa32171311d.png) Will there be such features for airmessage? doesnt need to have the same interface as imessage ![image (5)](https://user-images.githubusercontent.com/45743294/177019549-c6607371-fcfd-42d0-9c11-02165922b1f6.png) It could even look something simple like discord's And later on add to support to reply from airmessage. maybe a context menu on right click with the reply button.
Author
Owner

@tagavari commented on GitHub (Jul 3, 2022):

Currently, AirMessage Server will ignore message replies. The server can be updated to include message reply information and allow clients to display when a message is a reply. However, similar to tapbacks, AirMessage cannot allow the user to initiate replies without privilege escalation.

As this functionality would have to first be supported by AirMessage Server, this issue is also being moved there.

<!-- gh-comment-id:1173088772 --> @tagavari commented on GitHub (Jul 3, 2022): Currently, AirMessage Server will ignore message replies. The server can be updated to include message reply information and allow clients to display when a message is a reply. However, similar to tapbacks, AirMessage cannot allow the user to initiate replies without privilege escalation. As this functionality would have to first be supported by AirMessage Server, this issue is also being moved there.
Author
Owner

@sabogalc commented on GitHub (Jul 17, 2022):

Here is some information from @tneotia on supporting replies. Original link

@iandwelker in case you want to implement this:

  1. To render replies, you'd want to pull the thread_originator_guid column from chat.db. You can kinda see in here (the line renderer), here (the message bubble itself that decides whether the line should get rendered), and here (code that does some of the processing of whether the message is a reply, whether it should show the reply line, how that reply line is gonna look, etc)
  2. To send replies, refer to the following objc code:
// get the chat
    IMChat *chat = [BlueBubblesHelper getChat: data[@"chatGuid"]];
// get the message text
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: data[@"message"]];
// get the subject line, if any
    NSMutableAttributedString *subjectAttributedString = nil;
    if ([data objectForKey:(@"subject")] != [NSNull null]) {
        subjectAttributedString = [[NSMutableAttributedString alloc] initWithString: data[@"subject"]];
    }
// get the effect ID, if any
    NSString *effectId = nil;
    if ([data objectForKey:(@"effectId")] != [NSNull null]) {
        effectId = data[@"effectId"];
    }
    
// helper function to create a message
    void (^createMessage)(NSAttributedString*, NSAttributedString*, NSString*, NSString*) = ^(NSAttributedString *message, NSAttributedString *subject, NSString *effectId, NSString *threadIdentifier) {
// init an IMMessage with the text, subject, and effect ID
        IMMessage *messageToSend = [[IMMessage alloc] init];
        messageToSend = [messageToSend initWithSender:(nil) time:(nil) text:(message) messageSubject:(subject) fileTransferGUIDs:(nil) flags:(100005) error:(nil) guid:(nil) subject:(nil) balloonBundleID:(nil) payloadData:(nil) expressiveSendStyleID:(effectId)];
// add the thread ID for the reply
        messageToSend.threadIdentifier = threadIdentifier;
// send it
        [chat sendMessage:(messageToSend)];
    };
    
    if ([data objectForKey:(@"selectedMessageGuid")] != [NSNull null]) {
// get the message being replied to
        [BlueBubblesHelper getMessageItem:(chat) :(data[@"selectedMessageGuid"]) completionBlock:^(IMMessage *message) {
// get the specific IMMessagePartChatItem out of the message
            IMMessageItem *messageItem = (IMMessageItem *)message._imMessageItem;
            NSObject *items = messageItem._newChatItems;
            IMMessagePartChatItem *item;
            // sometimes items is an array so we need to account for that
            if ([items isKindOfClass:[NSArray class]]) {
                for(IMMessagePartChatItem* imci in (NSArray *)items) {
                    if([imci._item.guid isEqualToString:(data[@"selectedMessageGuid"])]) {
                        DLog(@"BLUEBUBBLESHELPER: %@", data[@"selectedMessageGuid"]);
                        item = imci;
                    }
                }
            } else {
                item = (IMMessagePartChatItem *)items;
            }
            NSString *identifier = @"";
// either reply to an existing thread or create a new thread
            if (message.threadIdentifier != nil) {
                identifier = message.threadIdentifier;
            } else {
                identifier = IMCreateThreadIdentifierForMessagePartChatItem(item);
            }
            createMessage(attributedString, subjectAttributedString, effectId, identifier);
        }];
    }

If you got more questions lmk!

<!-- gh-comment-id:1186591463 --> @sabogalc commented on GitHub (Jul 17, 2022): Here is some information from @tneotia on supporting replies. [Original link](https://github.com/iandwelker/smserver/issues/135#issuecomment-953390109) > @iandwelker in case you want to implement this: > > 1. To render replies, you'd want to pull the `thread_originator_guid` column from `chat.db`. You can kinda see in [here](https://github.com/BlueBubblesApp/bluebubbles-app/blob/development/lib/layouts/widgets/message_widget/reply_line_painter.dart) (the line renderer), [here](https://github.com/BlueBubblesApp/bluebubbles-app/blob/development/lib/layouts/widgets/message_widget/sent_message.dart#L753-L806) (the message bubble itself that decides whether the line should get rendered), and [here](https://github.com/BlueBubblesApp/bluebubbles-app/blob/development/lib/repository/models/io/message.dart#L909-L964) (code that does some of the processing of whether the message is a reply, whether it should show the reply line, how that reply line is gonna look, etc) > 2. To send replies, refer to the following objc code: > > ```objc > // get the chat > IMChat *chat = [BlueBubblesHelper getChat: data[@"chatGuid"]]; > // get the message text > NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: data[@"message"]]; > // get the subject line, if any > NSMutableAttributedString *subjectAttributedString = nil; > if ([data objectForKey:(@"subject")] != [NSNull null]) { > subjectAttributedString = [[NSMutableAttributedString alloc] initWithString: data[@"subject"]]; > } > // get the effect ID, if any > NSString *effectId = nil; > if ([data objectForKey:(@"effectId")] != [NSNull null]) { > effectId = data[@"effectId"]; > } > > // helper function to create a message > void (^createMessage)(NSAttributedString*, NSAttributedString*, NSString*, NSString*) = ^(NSAttributedString *message, NSAttributedString *subject, NSString *effectId, NSString *threadIdentifier) { > // init an IMMessage with the text, subject, and effect ID > IMMessage *messageToSend = [[IMMessage alloc] init]; > messageToSend = [messageToSend initWithSender:(nil) time:(nil) text:(message) messageSubject:(subject) fileTransferGUIDs:(nil) flags:(100005) error:(nil) guid:(nil) subject:(nil) balloonBundleID:(nil) payloadData:(nil) expressiveSendStyleID:(effectId)]; > // add the thread ID for the reply > messageToSend.threadIdentifier = threadIdentifier; > // send it > [chat sendMessage:(messageToSend)]; > }; > > if ([data objectForKey:(@"selectedMessageGuid")] != [NSNull null]) { > // get the message being replied to > [BlueBubblesHelper getMessageItem:(chat) :(data[@"selectedMessageGuid"]) completionBlock:^(IMMessage *message) { > // get the specific IMMessagePartChatItem out of the message > IMMessageItem *messageItem = (IMMessageItem *)message._imMessageItem; > NSObject *items = messageItem._newChatItems; > IMMessagePartChatItem *item; > // sometimes items is an array so we need to account for that > if ([items isKindOfClass:[NSArray class]]) { > for(IMMessagePartChatItem* imci in (NSArray *)items) { > if([imci._item.guid isEqualToString:(data[@"selectedMessageGuid"])]) { > DLog(@"BLUEBUBBLESHELPER: %@", data[@"selectedMessageGuid"]); > item = imci; > } > } > } else { > item = (IMMessagePartChatItem *)items; > } > NSString *identifier = @""; > // either reply to an existing thread or create a new thread > if (message.threadIdentifier != nil) { > identifier = message.threadIdentifier; > } else { > identifier = IMCreateThreadIdentifierForMessagePartChatItem(item); > } > createMessage(attributedString, subjectAttributedString, effectId, identifier); > }]; > } > ``` > > If you got more questions lmk!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/airmessage-server#18
No description provided.