Browse Source

Implement matrix->whatsapp formatting and fix whatsapp->matrix files

Tulir Asokan 6 years ago
parent
commit
b62a85a6df
2 changed files with 116 additions and 16 deletions
  1. 104 8
      portal.go
  2. 12 8
      user.go

+ 104 - 8
portal.go

@@ -28,6 +28,10 @@ import (
 	"sync"
 	"sync"
 	"net/http"
 	"net/http"
 	"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
 	"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
+	"mime"
+	"image"
+	"bytes"
+	"maunium.net/go/gomatrix/format"
 )
 )
 
 
 func (user *User) GetPortalByMXID(mxid types.MatrixRoomID) *Portal {
 func (user *User) GetPortalByMXID(mxid types.MatrixRoomID) *Portal {
@@ -130,8 +134,8 @@ func (portal *Portal) UpdateAvatar() bool {
 		return false
 		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 {
 	if err != nil {
 		portal.log.Errorln("Failed to upload avatar:", err)
 		portal.log.Errorln("Failed to upload avatar:", err)
 		return false
 		return false
@@ -278,6 +282,18 @@ func (portal *Portal) GetMessageIntent(info whatsapp.MessageInfo) *appservice.In
 	return puppet.Intent()
 	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) {
 func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) {
 	if portal.IsDuplicate(message.Info.Id) {
 	if portal.IsDuplicate(message.Info.Id) {
 		return
 		return
@@ -290,7 +306,11 @@ func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) {
 		return
 		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 {
 	if err != nil {
 		portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
 		portal.log.Errorfln("Failed to handle message %s: %v", message.Info.Id, err)
 		return
 		return
@@ -299,7 +319,7 @@ func (portal *Portal) HandleTextMessage(message whatsapp.TextMessage) {
 	portal.log.Debugln("Handled message", message.Info.Id, "->", resp.EventID)
 	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) {
 	if portal.IsDuplicate(info.Id) {
 		return
 		return
 	}
 	}
@@ -311,17 +331,65 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), info w
 		return
 		return
 	}
 	}
 
 
-	img, err := download()
+	data, err := download()
 	if err != nil {
 	if err != nil {
 		portal.log.Errorln("Failed to download media:", err)
 		portal.log.Errorln("Failed to download media:", err)
 		return
 		return
 	}
 	}
-	uploaded, err := intent.UploadBytes(img, mime)
+
+	uploaded, err := intent.UploadBytes(data, mimeType)
 	if err != nil {
 	if err != nil {
 		portal.log.Errorln("Failed to upload media:", err)
 		portal.log.Errorln("Failed to upload media:", err)
 		return
 		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 {
 	if err != nil {
 		portal.log.Errorfln("Failed to handle message %s: %v", info.Id, err)
 		portal.log.Errorfln("Failed to handle message %s: %v", info.Id, err)
 		return
 		return
@@ -330,12 +398,40 @@ func (portal *Portal) HandleMediaMessage(download func() ([]byte, error), info w
 	portal.log.Debugln("Handled message", info.Id, "->", resp.EventID)
 	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) {
 func (portal *Portal) HandleMatrixMessage(evt *gomatrix.Event) {
 	var err error
 	var err error
 	switch evt.Content.MsgType {
 	switch evt.Content.MsgType {
 	case gomatrix.MsgText:
 	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{
 		err = portal.user.Conn.Send(whatsapp.TextMessage{
-			Text: evt.Content.Body,
+			Text: text,
 			Info: whatsapp.MessageInfo{
 			Info: whatsapp.MessageInfo{
 				RemoteJid: portal.JID,
 				RemoteJid: portal.JID,
 			},
 			},

+ 12 - 8
user.go

@@ -24,7 +24,6 @@ import (
 	log "maunium.net/go/maulogger"
 	log "maunium.net/go/maulogger"
 	"maunium.net/go/mautrix-whatsapp/types"
 	"maunium.net/go/mautrix-whatsapp/types"
 	"strings"
 	"strings"
-	"encoding/json"
 	"sync"
 	"sync"
 	"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
 	"maunium.net/go/mautrix-whatsapp/whatsapp-ext"
 )
 )
@@ -186,10 +185,7 @@ func (user *User) Login(roomID types.MatrixRoomID) {
 func (user *User) Sync() {
 func (user *User) Sync() {
 	user.log.Debugln("Syncing...")
 	user.log.Debugln("Syncing...")
 	user.Conn.Contacts()
 	user.Conn.Contacts()
-	user.log.Debugln(user.Conn.Store.Contacts)
 	for jid, contact := range 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) {
 		if strings.HasSuffix(jid, puppetJIDStrippedSuffix) {
 			puppet := user.GetPuppetByJID(contact.Jid)
 			puppet := user.GetPuppetByJID(contact.Jid)
 			puppet.Sync(contact)
 			puppet.Sync(contact)
@@ -216,15 +212,23 @@ func (user *User) HandleTextMessage(message whatsapp.TextMessage) {
 }
 }
 
 
 func (user *User) HandleImageMessage(message whatsapp.ImageMessage) {
 func (user *User) HandleImageMessage(message whatsapp.ImageMessage) {
-	// user.log.Debugln("Received image message:", message)
 	portal := user.GetPortalByJID(message.Info.RemoteJid)
 	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) {
 func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) {
-	// user.log.Debugln("Received video message:", message)
 	portal := user.GetPortalByJID(message.Info.RemoteJid)
 	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) {
 func (user *User) HandleJsonMessage(message string) {