diff --git a/portal.go b/portal.go index 23dd7f4..336a086 100644 --- a/portal.go +++ b/portal.go @@ -28,6 +28,10 @@ import ( "sync" "net/http" "maunium.net/go/mautrix-whatsapp/whatsapp-ext" + "mime" + "image" + "bytes" + "maunium.net/go/gomatrix/format" ) func (user *User) GetPortalByMXID(mxid types.MatrixRoomID) *Portal { @@ -130,8 +134,8 @@ func (portal *Portal) UpdateAvatar() bool { return false } - mime := http.DetectContentType(data) - resp, err := portal.MainIntent().UploadBytes(data, mime) + mimeType := http.DetectContentType(data) + resp, err := portal.MainIntent().UploadBytes(data, mimeType) if err != nil { portal.log.Errorln("Failed to upload avatar:", err) return false @@ -278,6 +282,18 @@ func (portal *Portal) GetMessageIntent(info whatsapp.MessageInfo) *appservice.In return puppet.Intent() } +func (portal *Portal) GetRelations(info whatsapp.MessageInfo) (reply gomatrix.RelatesTo) { + if len(info.QuotedMessageID) == 0 { + return + } + message := portal.bridge.DB.Message.GetByJID(portal.Owner, info.QuotedMessageID) + if message != nil { + reply.InReplyTo.EventID = message.MXID + } + return + +} + func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) { if portal.IsDuplicate(message.Info.Id) { return @@ -290,7 +306,11 @@ func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) { return } - resp, err := intent.SendText(portal.MXID, message.Text) + resp, err := intent.SendMassagedMessageEvent(portal.MXID, gomatrix.EventMessage, gomatrix.Content{ + Body: message.Text, + MsgType: gomatrix.MsgText, + RelatesTo: portal.GetRelations(message.Info), + }, int64(message.Info.Timestamp*1000)) if err != nil { portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err) return @@ -299,7 +319,7 @@ func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) { portal.log.Debugln("Handled message", message.Info.Id, "->", resp.EventID) } -func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), info whatsapp.MessageInfo, mime, caption string) { +func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), thumbnail []byte, info whatsapp.MessageInfo, mimeType, caption string) { if portal.IsDuplicate(info.Id) { return } @@ -311,17 +331,65 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), info w return } - img, err := download() + data, err := download() if err != nil { portal.log.Errorln("Failed to download media:", err) return } - uploaded, err := intent.UploadBytes(img, mime) + + uploaded, err := intent.UploadBytes(data, mimeType) if err != nil { portal.log.Errorln("Failed to upload media:", err) return } - resp, err := intent.SendImage(portal.MXID, caption, uploaded.ContentURI) + if len(caption) == 0 { + caption = info.Id + exts, _ := mime.ExtensionsByType(mimeType) + if exts != nil && len(exts) > 0 { + caption += exts[0] + } + } + + content := gomatrix.Content{ + Body: caption, + URL: uploaded.ContentURI, + Info: gomatrix.FileInfo{ + Size: len(data), + MimeType: mimeType, + }, + RelatesTo: portal.GetRelations(info), + } + + if thumbnail != nil { + thumbnailMime := http.DetectContentType(thumbnail) + uploadedThumbnail, _ := intent.UploadBytes(thumbnail, thumbnailMime) + if uploadedThumbnail != nil { + content.Info.ThumbnailURL = uploadedThumbnail.ContentURI + cfg, _, _ := image.DecodeConfig(bytes.NewReader(data)) + content.Info.ThumbnailInfo = &gomatrix.FileInfo{ + Size: len(thumbnail), + Width: cfg.Width, + Height: cfg.Height, + MimeType: thumbnailMime, + } + } + } + + switch strings.ToLower(strings.Split(mimeType, "/")[0]) { + case "image": + content.MsgType = gomatrix.MsgImage + cfg, _, _ := image.DecodeConfig(bytes.NewReader(data)) + content.Info.Width = cfg.Width + content.Info.Height = cfg.Height + case "video": + content.MsgType = gomatrix.MsgVideo + case "audio": + content.MsgType = gomatrix.MsgAudio + default: + content.MsgType = gomatrix.MsgFile + } + + resp, err := intent.SendMassagedMessageEvent(portal.MXID, gomatrix.EventMessage, content, int64(info.Timestamp*1000)) if err != nil { portal.log.Errorfln("Failed to handle message %s: %v", info.Id, err) return @@ -330,12 +398,40 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), info w portal.log.Debugln("Handled message", info.Id, "->", resp.EventID) } +var htmlParser = format.HTMLParser{ + TabsToSpaces: 4, + Newline: "\n", + + PillConverter: func(mxid, eventID string) string { + return mxid + }, + BoldConverter: func(text string) string { + return fmt.Sprintf("*%s*", text) + }, + ItalicConverter: func(text string) string { + return fmt.Sprintf("_%s_", text) + }, + StrikethroughConverter: func(text string) string { + return fmt.Sprintf("~%s~", text) + }, + MonospaceConverter: func(text string) string { + return fmt.Sprintf("```%s```", text) + }, + MonospaceBlockConverter: func(text string) string { + return fmt.Sprintf("```%s```", text) + }, +} + func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) { var err error switch evt.Content.MsgType { case gomatrix.MsgText: + text := evt.Content.Body + if evt.Content.Format == gomatrix.FormatHTML { + text = htmlParser.Parse(evt.Content.FormattedBody) + } err = portal.user.Conn.Send(whatsapp.TextMessage{ - Text: evt.Content.Body, + Text: text, Info: whatsapp.MessageInfo{ RemoteJid: portal.JID, }, diff --git a/user.go b/user.go index a261e07..0c6102b 100644 --- a/user.go +++ b/user.go @@ -24,7 +24,6 @@ import ( log "maunium.net/go/maulogger" "maunium.net/go/mautrix-whatsapp/types" "strings" - "encoding/json" "sync" "maunium.net/go/mautrix-whatsapp/whatsapp-ext" ) @@ -186,10 +185,7 @@ func (user *User) Login(roomID types.MatrixRoomID) { func (user *User) Sync() { user.log.Debugln("Syncing...") user.Conn.Contacts() - user.log.Debugln(user.Conn.Store.Contacts) for jid, contact := range user.Conn.Store.Contacts { - dat, _ := json.Marshal(&contact) - user.log.Debugln(string(dat)) if strings.HasSuffix(jid, puppetJIDStrippedSuffix) { puppet := user.GetPuppetByJID(contact.Jid) puppet.Sync(contact) @@ -216,15 +212,23 @@ func (user *User) HandleTextMessage(message whatsapp.TextMessage) { } func (user *User) HandleImageMessage(message whatsapp.ImageMessage) { - // user.log.Debugln("Received image message:", message) portal := user.GetPortalByJID(message.Info.RemoteJid) - portal.HandleMediaMessage(message.Download, message.Info, message.Type, message.Caption) + portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Caption) } func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) { - // user.log.Debugln("Received video message:", message) portal := user.GetPortalByJID(message.Info.RemoteJid) - portal.HandleMediaMessage(message.Download, message.Info, message.Type, message.Caption) + portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Caption) +} + +func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) { + portal := user.GetPortalByJID(message.Info.RemoteJid) + portal.HandleMediaMessage(message.Download, nil, message.Info, message.Type, "") +} + +func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) { + portal := user.GetPortalByJID(message.Info.RemoteJid) + portal.HandleMediaMessage(message.Download, message.Thumbnail, message.Info, message.Type, message.Title) } func (user *User) HandleJsonMessage(message string) {