From 9671b6c39a89adb31e0160e5adafd88fac8ec247 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 31 Jul 2020 14:30:58 +0300 Subject: [PATCH] Use MentionedJIDs metadata instead of assuming everything is a mention --- formatting.go | 44 ++++++++++++++++++++++++++------------------ go.mod | 4 ++-- go.sum | 4 ++++ portal.go | 21 +++++++++++++-------- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/formatting.go b/formatting.go index 7880790..478fd1a 100644 --- a/formatting.go +++ b/formatting.go @@ -34,7 +34,8 @@ var italicRegex = regexp.MustCompile("([\\s>~*]|^)_(.+?)_([^a-zA-Z\\d]|$)") var boldRegex = regexp.MustCompile("([\\s>_~]|^)\\*(.+?)\\*([^a-zA-Z\\d]|$)") var strikethroughRegex = regexp.MustCompile("([\\s>_*]|^)~(.+?)~([^a-zA-Z\\d]|$)") var codeBlockRegex = regexp.MustCompile("```(?:.|\n)+?```") -var mentionRegex = regexp.MustCompile("@[0-9]+") + +const mentionedJIDsContextKey = "net.maunium.whatsapp.mentioned_jids" type Formatter struct { bridge *Bridge @@ -53,28 +54,34 @@ func NewFormatter(bridge *Bridge) *Formatter { TabsToSpaces: 4, Newline: "\n", - PillConverter: func(mxid, eventID string) string { + PillConverter: func(mxid, eventID string, ctx format.Context) string { if mxid[0] == '@' { puppet := bridge.GetPuppetByMXID(id.UserID(mxid)) if puppet != nil { + jids, ok := ctx[mentionedJIDsContextKey].([]types.WhatsAppID) + if !ok { + ctx[mentionedJIDsContextKey] = []types.WhatsAppID{puppet.JID} + } else { + ctx[mentionedJIDsContextKey] = append(jids, puppet.JID) + } return "@" + puppet.PhoneNumber() } } return mxid }, - BoldConverter: func(text string) string { + BoldConverter: func(text string, _ format.Context) string { return fmt.Sprintf("*%s*", text) }, - ItalicConverter: func(text string) string { + ItalicConverter: func(text string, _ format.Context) string { return fmt.Sprintf("_%s_", text) }, - StrikethroughConverter: func(text string) string { + StrikethroughConverter: func(text string, _ format.Context) string { return fmt.Sprintf("~%s~", text) }, - MonospaceConverter: func(text string) string { + MonospaceConverter: func(text string, _ format.Context) string { return fmt.Sprintf("```%s```", text) }, - MonospaceBlockConverter: func(text, language string) string { + MonospaceBlockConverter: func(text, language string, _ format.Context) string { return fmt.Sprintf("```%s```", text) }, }, @@ -92,16 +99,8 @@ func NewFormatter(bridge *Bridge) *Formatter { } return fmt.Sprintf("%s", str) }, - mentionRegex: func(str string) string { - mxid, displayname := formatter.getMatrixInfoByJID(str[1:] + whatsappExt.NewUserSuffix) - return fmt.Sprintf(`%s`, mxid, displayname) - }, } formatter.waReplFuncText = map[*regexp.Regexp]func(string) string{ - mentionRegex: func(str string) string { - _, displayname := formatter.getMatrixInfoByJID(str[1:] + whatsappExt.NewUserSuffix) - return displayname - }, } return formatter } @@ -117,7 +116,7 @@ func (formatter *Formatter) getMatrixInfoByJID(jid types.WhatsAppID) (mxid id.Us return } -func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) { +func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, mentionedJIDs []types.WhatsAppID) { output := html.EscapeString(content.Body) for regex, replacement := range formatter.waReplString { output = regex.ReplaceAllString(output, replacement) @@ -125,6 +124,12 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) { for regex, replacer := range formatter.waReplFunc { output = regex.ReplaceAllStringFunc(output, replacer) } + for _, jid := range mentionedJIDs { + mxid, displayname := formatter.getMatrixInfoByJID(jid) + number := "@" + strings.Replace(jid, whatsappExt.NewUserSuffix, "", 1) + output = strings.Replace(output, number, fmt.Sprintf(`%s`, mxid, displayname), -1) + content.Body = strings.Replace(content.Body, number, displayname, -1) + } if output != content.Body { output = strings.Replace(output, "\n", "
", -1) content.FormattedBody = output @@ -135,6 +140,9 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) { } } -func (formatter *Formatter) ParseMatrix(html string) string { - return formatter.matrixHTMLParser.Parse(html) +func (formatter *Formatter) ParseMatrix(html string) (string, []types.WhatsAppID) { + ctx := make(format.Context) + result := formatter.matrixHTMLParser.Parse(html, ctx) + mentionedJIDs := ctx[mentionedJIDsContextKey].([]types.WhatsAppID) + return result, mentionedJIDs } diff --git a/go.mod b/go.mod index ce09146..0ffed15 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( gopkg.in/yaml.v2 v2.3.0 maunium.net/go/mauflag v1.0.0 maunium.net/go/maulogger/v2 v2.1.1 - maunium.net/go/mautrix v0.6.1 + maunium.net/go/mautrix v0.7.0-rc.2 ) -replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.6 +replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.7 diff --git a/go.sum b/go.sum index d41785f..c52ba65 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,8 @@ github.com/tulir/go-whatsapp v0.3.5 h1:cFw8MWhoLTqR0h2kSkSvz866rggRIAx4X2l8I65gA github.com/tulir/go-whatsapp v0.3.5/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM= github.com/tulir/go-whatsapp v0.3.6 h1:RtyNh8TFX48ClMvi2J8oS3qmH7b1t9SIKA5jucG2lbk= github.com/tulir/go-whatsapp v0.3.6/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM= +github.com/tulir/go-whatsapp v0.3.7 h1:6YoHsAlO+Y1SnU0bOntDmuvJQziEnBjFKO+1fOH2VIw= +github.com/tulir/go-whatsapp v0.3.7/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= @@ -212,3 +214,5 @@ maunium.net/go/mautrix v0.6.0 h1:V32l4aygKk2XcH3fi8Yd0pFeSyYZJNRIvr8vdA2GtC8= maunium.net/go/mautrix v0.6.0/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= maunium.net/go/mautrix v0.6.1 h1:OFxAEnjEtkstE5J3RLv+vVrUORY6UTXV8pD/qWRBTPI= maunium.net/go/mautrix v0.6.1/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= +maunium.net/go/mautrix v0.7.0-rc.2 h1:139raRbbLft9i+g0zGVOT8rrHKRQmeo0SsZnFpZDEXE= +maunium.net/go/mautrix v0.7.0-rc.2/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= diff --git a/portal.go b/portal.go index 53a495c..89c2b58 100644 --- a/portal.go +++ b/portal.go @@ -1189,7 +1189,7 @@ func (portal *Portal) HandleTextMessage(source *User, message whatsapp.TextMessa MsgType: event.MsgText, } - portal.bridge.Formatter.ParseWhatsApp(content) + portal.bridge.Formatter.ParseWhatsApp(content, message.ContextInfo.MentionedJID) portal.SetReply(content, message.ContextInfo) _, _ = intent.UserTyping(portal.MXID, false, 0) @@ -1554,7 +1554,7 @@ func (portal *Portal) HandleMediaMessage(source *User, msg mediaMessage) { MsgType: event.MsgNotice, } - portal.bridge.Formatter.ParseWhatsApp(captionContent) + portal.bridge.Formatter.ParseWhatsApp(captionContent, msg.context.MentionedJID) _, err := portal.sendMessage(intent, event.EventMessage, captionContent, ts) if err != nil { @@ -1658,8 +1658,9 @@ func (portal *Portal) convertGifToVideo(gif []byte) ([]byte, error) { func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsapp.MediaType) *MediaUpload { var caption string + var mentionedJIDs []types.WhatsAppID if relaybotFormatted { - caption = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) + caption, mentionedJIDs = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) } var file *event.EncryptedFileInfo @@ -1702,6 +1703,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool return &MediaUpload{ Caption: caption, + MentionedJIDs: mentionedJIDs, URL: url, MediaKey: mediaKey, FileEncSHA256: fileEncSHA256, @@ -1713,6 +1715,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool type MediaUpload struct { Caption string + MentionedJIDs []types.WhatsAppID URL string MediaKey []byte FileEncSHA256 []byte @@ -1819,15 +1822,11 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP case event.MsgText, event.MsgEmote, event.MsgNotice: text := content.Body if content.Format == event.FormatHTML { - text = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) + text, ctxInfo.MentionedJid = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) } if content.MsgType == event.MsgEmote && !relaybotFormatted { text = "/me " + text } - ctxInfo.MentionedJid = mentionRegex.FindAllString(text, -1) - for index, mention := range ctxInfo.MentionedJid { - ctxInfo.MentionedJid[index] = mention[1:] + whatsappExt.NewUserSuffix - } if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil { info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{ Text: &text, @@ -1841,7 +1840,9 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP if media == nil { return nil, sender } + ctxInfo.MentionedJid = media.MentionedJIDs info.Message.ImageMessage = &waProto.ImageMessage{ + ContextInfo: ctxInfo, Caption: &media.Caption, JpegThumbnail: media.Thumbnail, Url: &media.URL, @@ -1858,7 +1859,9 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP return nil, sender } duration := uint32(content.GetInfo().Duration) + ctxInfo.MentionedJid = media.MentionedJIDs info.Message.VideoMessage = &waProto.VideoMessage{ + ContextInfo: ctxInfo, Caption: &media.Caption, JpegThumbnail: media.Thumbnail, Url: &media.URL, @@ -1877,6 +1880,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP } duration := uint32(content.GetInfo().Duration) info.Message.AudioMessage = &waProto.AudioMessage{ + ContextInfo: ctxInfo, Url: &media.URL, MediaKey: media.MediaKey, Mimetype: &content.GetInfo().MimeType, @@ -1891,6 +1895,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP return nil, sender } info.Message.DocumentMessage = &waProto.DocumentMessage{ + ContextInfo: ctxInfo, Url: &media.URL, FileName: &content.Body, MediaKey: media.MediaKey,