mautrix / imessage

A Matrix-iMessage puppeting bridge
https://go.mau.fi/mautrix-imessage/
GNU Affero General Public License v3.0
332 stars 36 forks source link

[bluebubbles] Implement handleChatReadStatusChanged #166

Closed cnuss closed 5 months ago

trek-boldly-go commented 5 months ago

@cnuss I was just looking at this function and noticed it is already filled out, but I am not sure it is correct (even though it seems to be working).

Specifically, I am thinking about the sender and the IsFromMe field of the imessage.ReadReceipt object below:

    lastMessage, err := bb.getMessage(chatInfo.Data.LastMessage.GUID)
    if err != nil {
        bb.log.Warn().Err(err).Msg("Failed to get last message")
        return nil
    }

    var now = time.Now()

    var receipt = imessage.ReadReceipt{
        SenderGUID:     lastMessage.Handle.Address, // TODO: Make sure this is the right field?
        IsFromMe:       true,
        ChatGUID:       rec.ChatGUID,
        ReadUpTo:       chatInfo.Data.LastMessage.GUID,
        ReadAt:         now,
        JSONUnixReadAt: timeToFloat(now),
    }

From what I have seen, I can't prove that the Handle is always the sender of a message. I'd have to test this again, but I think once I found the Handle was the recipient and I was very confused, hence my TODO in the helper conversion function:

func (bb *blueBubbles) convertBBMessageToiMessage(bbMessage Message) (*imessage.Message, error) {

    var message imessage.Message

    // Convert bluebubbles.Message to imessage.Message
    message.GUID = bbMessage.GUID
    message.Time = time.Unix(0, bbMessage.DateCreated*int64(time.Millisecond))
    message.Subject = bbMessage.Subject
    message.Text = bbMessage.Text
    message.ChatGUID = bbMessage.Chats[0].GUID

    // TODO: there doesn't seem to be a "from" in the bluebubbles data
    // message.JSONSenderGUID = bbMessage.Handle.Address
    // message.Sender = imessage.Identifier{
    //  LocalID: bbMessage.Handle.Address,
    //  Service: bbMessage.Handle.Service,
    //  IsGroup: false,
    // }

    message.JSONTargetGUID = bbMessage.Handle.Address
    message.Target = imessage.Identifier{
        LocalID: bbMessage.Handle.Address,
        Service: bbMessage.Handle.Service,
        IsGroup: false,
    }
    message.Service = bbMessage.Handle.Service
    message.IsFromMe = bbMessage.IsFromMe
    message.IsRead = false
    if message.IsRead {
        message.ReadAt = time.Unix(0, bbMessage.DateRead*int64(time.Millisecond))
    }
    message.IsDelivered = true
    message.IsSent = true
    message.IsEmote = false
    message.IsAudioMessage = bbMessage.IsAudioMessage

    // TODO: ReplyTo
    // message.ReplyToGUID = bbMessage.ThreadOriginatorGuid
    // message.ReplyToPart = bbMessage.PartCount

    // TODO: Tapbacks
    // if bbMessage.AssociatedMessageGuid != nil {
    //  message.Tapback = &imessage.Tapback{
    //      TargetGUID: *bbMessage.AssociatedMessageGuid,
    //  }
    //  message.Tapback.Parse()
    // } else {
    //  message.Tapback = nil
    // }

    message.Attachments = make([]*imessage.Attachment, len(bbMessage.Attachments))
    for i, blueBubblesAttachment := range bbMessage.Attachments {
        attachment, err := bb.convertAttachment(blueBubblesAttachment)
        if err != nil {
            bb.log.Warn().Err(err).Msg("Error converting attachment")
            continue
        }
        message.Attachments[i] = attachment
    }

    message.GroupActionType = imessage.GroupActionType(bbMessage.GroupActionType)
    message.NewGroupName = bbMessage.GroupTitle
    message.ThreadID = bbMessage.ThreadOriginatorGuid

    return &message, nil
}

I am also puzzled at the IsFromMe set to true all the time, I don't think BBs would send the webhook when you read your own message.

And while I am thinking about it, what does BBs do for an iMessage group chat? The event from BBs doesn't say who read it, so you are looking for who sent the last message. At the time it sends the event, the other person likely hasn't yet sent a reply, so I guess you will always get your own message. If you are in a group chat, what happens when one of the others has read your message, but no one else? Does BBs suddenly include the other person then? 2024-01-17T12:46:50-06:00 TRC handleChatReadStatusChanged component=bluebubbles data={"chatGuid":"iMessage;-;example@gmail.com","read":true}

TL;DR

  1. Why is IsFromMe always true
  2. Getting the last sent message probably isn't from the person that just read the convo (probably your own message)
  3. How does BBs handle group chats, because they would almost have to include who the reader is
cnuss commented 5 months ago
  1. I was guessing and didn't know what to set it to
  2. Probably, more guessing was here to fill out the fields
  3. I think running bluebubbles.app/web with devtools on would be helpful

buy in large, lots of guesswork on the field mapping. I think it'd be worth firing up sh-imessage in mac-nosip mode and debug logging actual to find out what we expect to toss in

trek-boldly-go commented 5 months ago
  1. I flipped this boolean because I don't think BB will send an event for a read chat unless it was read by someone else
  2. I guess it's fine for now because even when you get your own message, the bbmessage.Handle is still the other person
  3. I am not in any group chats so I can't really trigger this. And the web app won't help because this data comes from thee websocket and not an API request

So I am closing this for now because it seemed to work for me anyway in one chat I had. If someone else has more problems, we can open another issue in the future.