From 32c0d74832e548caed3e2af659570a1c8ecb2376 Mon Sep 17 00:00:00 2001 From: Gianluca Iavicoli Date: Sat, 28 Mar 2026 15:06:43 +0100 Subject: [PATCH 1/3] fix: populate quoted message content in replies sent to WhatsApp --- pkg/msgconv/from-matrix.go | 59 +++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 49f60486..5e589d0b 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -62,7 +62,7 @@ func (mc *MessageConverter) generateContextInfo( if err == nil { contextInfo.StanzaID = proto.String(msgID.ID) contextInfo.Participant = proto.String(msgID.Sender.String()) - contextInfo.QuotedMessage = &waE2E.Message{Conversation: proto.String("")} + contextInfo.QuotedMessage = mc.fetchQuotedMessage(ctx, portal, replyTo) contextInfo.QuotedType = waE2E.ContextInfo_EXPLICIT.Enum() } else { zerolog.Ctx(ctx).Warn().Err(err). @@ -90,6 +90,63 @@ func (mc *MessageConverter) generateContextInfo( return contextInfo } +func (mc *MessageConverter) fetchQuotedMessage(ctx context.Context, portal *bridgev2.Portal, replyTo *database.Message) *waE2E.Message { + evt, err := mc.Bridge.Matrix.BotIntent().GetEvent(ctx, portal.MXID, replyTo.MXID) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err). + Stringer("reply_to_event_id", replyTo.MXID). + Msg("Failed to fetch quoted event from Matrix") + return &waE2E.Message{Conversation: proto.String("")} + } + if evt.Content.Parsed == nil { + err = evt.Content.ParseRaw(evt.Type) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err). + Stringer("reply_to_event_id", replyTo.MXID). + Msg("Failed to parse quoted event content") + return &waE2E.Message{Conversation: proto.String("")} + } + } + content, ok := evt.Content.Parsed.(*event.MessageEventContent) + if !ok { + return &waE2E.Message{Conversation: proto.String("")} + } + switch content.MsgType { + case event.MsgText, event.MsgNotice, event.MsgEmote: + return &waE2E.Message{Conversation: proto.String(content.Body)} + case event.MsgImage, event.MessageType(event.EventSticker.Type): + return &waE2E.Message{ImageMessage: &waE2E.ImageMessage{ + Caption: proto.String(content.Body), + Mimetype: proto.String(content.GetInfo().MimeType), + }} + case event.MsgVideo: + return &waE2E.Message{VideoMessage: &waE2E.VideoMessage{ + Caption: proto.String(content.Body), + Mimetype: proto.String(content.GetInfo().MimeType), + }} + case event.MsgAudio: + return &waE2E.Message{AudioMessage: &waE2E.AudioMessage{ + Mimetype: proto.String(content.GetInfo().MimeType), + }} + case event.MsgFile: + return &waE2E.Message{DocumentMessage: &waE2E.DocumentMessage{ + Title: proto.String(content.Body), + Mimetype: proto.String(content.GetInfo().MimeType), + }} + case event.MsgLocation: + lat, long, geoErr := parseGeoURI(content.GeoURI) + if geoErr != nil { + return &waE2E.Message{Conversation: proto.String(content.Body)} + } + return &waE2E.Message{LocationMessage: &waE2E.LocationMessage{ + DegreesLatitude: &lat, + DegreesLongitude: &long, + }} + default: + return &waE2E.Message{Conversation: proto.String(content.Body)} + } +} + func (mc *MessageConverter) ToWhatsApp( ctx context.Context, client *whatsmeow.Client, From aab93430395de34b20c35edee9b1aec70a21a00d Mon Sep 17 00:00:00 2001 From: Gianluca Iavicoli Date: Sat, 28 Mar 2026 15:09:14 +0100 Subject: [PATCH 2/3] chore: add debug log for non-message quoted events --- pkg/msgconv/from-matrix.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 5e589d0b..e2a9dff2 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -109,6 +109,9 @@ func (mc *MessageConverter) fetchQuotedMessage(ctx context.Context, portal *brid } content, ok := evt.Content.Parsed.(*event.MessageEventContent) if !ok { + zerolog.Ctx(ctx).Debug(). + Stringer("reply_to_event_id", replyTo.MXID). + Msg("Quoted event is not a message, using empty quoted message") return &waE2E.Message{Conversation: proto.String("")} } switch content.MsgType { From 4a3b70c088a0e2677fad2ec211c42bdc645c599b Mon Sep 17 00:00:00 2001 From: Gianluca Iavicoli Date: Sat, 28 Mar 2026 19:33:37 +0100 Subject: [PATCH 3/3] fix: handle sticker and poll quoted messages in replies --- pkg/msgconv/from-matrix.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index e2a9dff2..2aa8fd16 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -107,6 +107,9 @@ func (mc *MessageConverter) fetchQuotedMessage(ctx context.Context, portal *brid return &waE2E.Message{Conversation: proto.String("")} } } + if pollContent, ok := evt.Content.Parsed.(*event.PollStartEventContent); ok { + return &waE2E.Message{Conversation: proto.String(pollContent.PollStart.Question.Text)} + } content, ok := evt.Content.Parsed.(*event.MessageEventContent) if !ok { zerolog.Ctx(ctx).Debug(). @@ -114,10 +117,24 @@ func (mc *MessageConverter) fetchQuotedMessage(ctx context.Context, portal *brid Msg("Quoted event is not a message, using empty quoted message") return &waE2E.Message{Conversation: proto.String("")} } + if evt.Type == event.EventSticker { + stickerMsg := &waE2E.StickerMessage{ + Mimetype: proto.String(content.GetInfo().MimeType), + } + data, err := mc.Bridge.Bot.DownloadMedia(ctx, content.URL, content.File) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err). + Stringer("reply_to_event_id", replyTo.MXID). + Msg("Failed to download sticker for quoted message") + } else { + stickerMsg.PngThumbnail = data + } + return &waE2E.Message{StickerMessage: stickerMsg} + } switch content.MsgType { case event.MsgText, event.MsgNotice, event.MsgEmote: return &waE2E.Message{Conversation: proto.String(content.Body)} - case event.MsgImage, event.MessageType(event.EventSticker.Type): + case event.MsgImage: return &waE2E.Message{ImageMessage: &waE2E.ImageMessage{ Caption: proto.String(content.Body), Mimetype: proto.String(content.GetInfo().MimeType),