Skip to content

Commit

Permalink
Parse newsletter edits properly
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Oct 18, 2023
1 parent 9ac5986 commit 1372115
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 23 deletions.
20 changes: 20 additions & 0 deletions binary/attrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ func (au *AttrUtility) GetUnixTime(key string, require bool) (time.Time, bool) {
}
}

func (au *AttrUtility) GetUnixMilli(key string, require bool) (time.Time, bool) {
if intVal, ok := au.GetInt64(key, require); !ok {
return time.Time{}, false
} else if intVal == 0 {
return time.Time{}, true
} else {
return time.UnixMilli(intVal), true
}
}

// OptionalString returns the string under the given key.
func (au *AttrUtility) OptionalString(key string) string {
strVal, _ := au.GetString(key, false)
Expand Down Expand Up @@ -176,6 +186,16 @@ func (au *AttrUtility) UnixTime(key string) time.Time {
return val
}

func (au *AttrUtility) OptionalUnixMilli(key string) time.Time {
val, _ := au.GetUnixMilli(key, false)
return val
}

func (au *AttrUtility) UnixMilli(key string) time.Time {
val, _ := au.GetUnixMilli(key, true)
return val
}

// OK returns true if there are no errors.
func (au *AttrUtility) OK() bool {
return len(au.Errors) == 0
Expand Down
21 changes: 18 additions & 3 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func (cli *Client) parseMessageInfo(node *waBinary.Node) (*types.MessageInfo, er
info.PushName = ag.OptionalString("notify")
info.Category = ag.OptionalString("category")
info.Type = ag.OptionalString("type")
info.Edit = types.EditAttribute(ag.OptionalString("edit"))
if !ag.OK() {
return nil, ag.Error()
}
Expand Down Expand Up @@ -149,9 +150,19 @@ func (cli *Client) handlePlaintextMessage(info *types.MessageInfo, node *waBinar
cli.Log.Warnf("Error unmarshaling plaintext message from %s: %v", info.SourceString(), err)
return
}
cli.handleDecryptedMessage(info, &msg, 0)
// TODO do these need receipts?
//go cli.sendMessageReceipt(info)
cli.storeMessageSecret(info, &msg)
evt := &events.Message{
Info: *info,
RawMessage: &msg,
}
meta, ok := node.GetOptionalChildByTag("meta")
if ok {
evt.NewsletterMeta = &events.NewsletterMessageMeta{
EditTS: meta.AttrGetter().UnixMilli("msg_edit_t"),
OriginalTS: meta.AttrGetter().UnixTime("original_msg_t"),
}
}
cli.dispatchEvent(evt.UnwrapRaw())
return
}

Expand Down Expand Up @@ -460,6 +471,10 @@ func (cli *Client) processProtocolParts(info *types.MessageInfo, msg *waProto.Me
if msg.GetProtocolMessage() != nil {
cli.handleProtocolMessage(info, msg)
}
cli.storeMessageSecret(info, msg)
}

func (cli *Client) storeMessageSecret(info *types.MessageInfo, msg *waProto.Message) {
if msgSecret := msg.GetMessageContextInfo().GetMessageSecret(); len(msgSecret) > 0 {
err := cli.Store.MsgSecrets.PutMessageSecret(info.Chat, info.Sender, info.ID, msgSecret)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion newsletter.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (cli *Client) NewsletterSendReaction(jid types.JID, serverID types.MessageS
if reaction != "" {
reactionAttrs["code"] = reaction
} else {
messageAttrs["edit"] = EditAttributeSenderRevoke
messageAttrs["edit"] = string(types.EditAttributeSenderRevoke)
}
return cli.sendNode(waBinary.Node{
Tag: "message",
Expand Down
29 changes: 10 additions & 19 deletions send.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,10 @@ func (cli *Client) sendNewsletter(to types.JID, id types.MessageID, message *waP
}
if message.EditedMessage != nil {
attrs["id"] = types.MessageID(message.GetEditedMessage().GetMessage().GetProtocolMessage().GetKey().GetId())
attrs["edit"] = EditAttributeAdminEdit
attrs["edit"] = string(types.EditAttributeAdminEdit)
message = message.GetEditedMessage().GetMessage().GetProtocolMessage().GetEditedMessage()
} else if message.ProtocolMessage != nil && message.ProtocolMessage.GetType() == waProto.ProtocolMessage_REVOKE {
attrs["edit"] = EditAttributeAdminRevoke
attrs["edit"] = string(types.EditAttributeAdminRevoke)
attrs["id"] = types.MessageID(message.GetProtocolMessage().GetKey().GetId())
message = nil
}
Expand Down Expand Up @@ -698,40 +698,31 @@ func getButtonAttributes(msg *waProto.Message) waBinary.Attrs {
}
}

const (
EditAttributeEmpty = ""
EditAttributeMessageEdit = "1"
EditAttributePinInChat = "2"
EditAttributeAdminEdit = "3"
EditAttributeSenderRevoke = "7"
EditAttributeAdminRevoke = "8"
)

const RemoveReactionText = ""

func getEditAttribute(msg *waProto.Message) string {
func getEditAttribute(msg *waProto.Message) types.EditAttribute {
switch {
case msg.EditedMessage != nil && msg.EditedMessage.Message != nil:
return getEditAttribute(msg.EditedMessage.Message)
case msg.ProtocolMessage != nil && msg.ProtocolMessage.GetKey() != nil:
switch msg.ProtocolMessage.GetType() {
case waProto.ProtocolMessage_REVOKE:
if msg.ProtocolMessage.GetKey().GetFromMe() {
return EditAttributeSenderRevoke
return types.EditAttributeSenderRevoke
} else {
return EditAttributeAdminRevoke
return types.EditAttributeAdminRevoke
}
case waProto.ProtocolMessage_MESSAGE_EDIT:
if msg.ProtocolMessage.EditedMessage != nil {
return EditAttributeMessageEdit
return types.EditAttributeMessageEdit
}
}
case msg.ReactionMessage != nil && msg.ReactionMessage.GetText() == RemoveReactionText:
return EditAttributeSenderRevoke
return types.EditAttributeSenderRevoke
case msg.KeepInChatMessage != nil && msg.KeepInChatMessage.GetKey().GetFromMe() && msg.KeepInChatMessage.GetKeepType() == waProto.KeepType_UNDO_KEEP_FOR_ALL:
return EditAttributeSenderRevoke
return types.EditAttributeSenderRevoke
}
return EditAttributeEmpty
return types.EditAttributeEmpty
}

func (cli *Client) preparePeerMessageNode(to types.JID, id types.MessageID, message *waProto.Message, timings *MessageDebugTimings) (*waBinary.Node, error) {
Expand Down Expand Up @@ -817,7 +808,7 @@ func (cli *Client) prepareMessageNode(ctx context.Context, to, ownID types.JID,
"to": to,
}
if editAttr := getEditAttribute(message); editAttr != "" {
attrs["edit"] = editAttr
attrs["edit"] = string(editAttr)
encAttrs["decrypt-fail"] = string(events.DecryptFailHide)
}
if msgType == "reaction" {
Expand Down
10 changes: 10 additions & 0 deletions types/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ type UndecryptableMessage struct {
DecryptFailMode DecryptFailMode
}

type NewsletterMessageMeta struct {
// When a newsletter message is edited, the message isn't wrapped in an EditedMessage like normal messages.
// Instead, the message is the new content, the ID is the original message ID, and the edit timestamp is here.
EditTS time.Time
// This is the timestamp of the original message for edits.
OriginalTS time.Time
}

// Message is emitted when receiving a new message.
type Message struct {
Info types.MessageInfo // Information about the message like the chat and sender IDs
Expand All @@ -239,6 +247,8 @@ type Message struct {
// If the message was re-requested from the sender, this is the number of retries it took.
RetryCount int

NewsletterMeta *NewsletterMessageMeta

// The raw message struct. This is the raw unmodified data, which means the actual message might
// be wrapped in DeviceSentMessage, EphemeralMessage or ViewOnceMessage.
RawMessage *waProto.Message
Expand Down
12 changes: 12 additions & 0 deletions types/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ type DeviceSentMeta struct {
Phash string
}

type EditAttribute string

const (
EditAttributeEmpty EditAttribute = ""
EditAttributeMessageEdit EditAttribute = "1"
EditAttributePinInChat EditAttribute = "2"
EditAttributeAdminEdit EditAttribute = "3" // only used in newsletters
EditAttributeSenderRevoke EditAttribute = "7"
EditAttributeAdminRevoke EditAttribute = "8"
)

// MessageInfo contains metadata about an incoming message.
type MessageInfo struct {
MessageSource
Expand All @@ -47,6 +58,7 @@ type MessageInfo struct {
Category string
Multicast bool
MediaType string
Edit EditAttribute

VerifiedName *VerifiedName
DeviceSentMeta *DeviceSentMeta // Metadata for direct messages sent from another one of the user's own devices.
Expand Down

0 comments on commit 1372115

Please sign in to comment.