From 7ee5aa647cd8a35881b4ea2d4e6c0f9067e48097 Mon Sep 17 00:00:00 2001 From: Kishan Bagaria <1093313+KishanBagaria@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:02:48 -0700 Subject: [PATCH 1/2] - --- pkg/connector/wamsgtype.go | 2 + pkg/msgconv/from-whatsapp.go | 4 ++ pkg/msgconv/wa-misc.go | 81 ++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/pkg/connector/wamsgtype.go b/pkg/connector/wamsgtype.go index 92e7f86..e716f5d 100644 --- a/pkg/connector/wamsgtype.go +++ b/pkg/connector/wamsgtype.go @@ -132,6 +132,8 @@ func getMessageType(waMsg *waE2E.Message) string { return "poll result snapshot" case waMsg.MessageHistoryBundle != nil: return "message history bundle" + case waMsg.MessageHistoryNotice != nil: + return "message history notice" case waMsg.RequestPhoneNumberMessage != nil: return "request phone number" case waMsg.KeepInChatMessage != nil: diff --git a/pkg/msgconv/from-whatsapp.go b/pkg/msgconv/from-whatsapp.go index 11569e2..2117535 100644 --- a/pkg/msgconv/from-whatsapp.go +++ b/pkg/msgconv/from-whatsapp.go @@ -217,6 +217,10 @@ func (mc *MessageConverter) ToMatrix( part, contextInfo = mc.convertGroupInviteMessage(ctx, info, waMsg.GroupInviteMessage) case waMsg.ProtocolMessage != nil && waMsg.ProtocolMessage.GetType() == waE2E.ProtocolMessage_EPHEMERAL_SETTING: part, contextInfo = mc.convertEphemeralSettingMessage(ctx, waMsg.ProtocolMessage, info.Timestamp, isBackfill) + case waMsg.MessageHistoryBundle != nil: + part, contextInfo = mc.convertMessageHistoryShare(ctx, info, waMsg.MessageHistoryBundle.GetMessageHistoryMetadata(), waMsg.MessageHistoryBundle.GetContextInfo()) + case waMsg.MessageHistoryNotice != nil: + part, contextInfo = mc.convertMessageHistoryShare(ctx, info, waMsg.MessageHistoryNotice.GetMessageHistoryMetadata(), waMsg.MessageHistoryNotice.GetContextInfo()) case waMsg.EncCommentMessage != nil: part = failedCommentPart default: diff --git a/pkg/msgconv/wa-misc.go b/pkg/msgconv/wa-misc.go index 7ca4427..9222f78 100644 --- a/pkg/msgconv/wa-misc.go +++ b/pkg/msgconv/wa-misc.go @@ -21,6 +21,7 @@ import ( "encoding/base64" "fmt" "html/template" + "slices" "strings" "time" @@ -73,6 +74,86 @@ func (mc *MessageConverter) convertPlaceholderMessage(ctx context.Context, rawMs } } +func joinNaturalNames(names []string) string { + names = slices.DeleteFunc(names, func(name string) bool { + return name == "" + }) + switch len(names) { + case 0: + return "" + case 1: + return names[0] + case 2: + return names[0] + " and " + names[1] + default: + return strings.Join(names[:len(names)-1], ", ") + ", and " + names[len(names)-1] + } +} + +func (mc *MessageConverter) getHistoryReceiverName(ctx context.Context, receiver string) string { + jid, err := types.ParseJID(receiver) + if err != nil { + zerolog.Ctx(ctx).Err(err).Str("receiver_jid", receiver).Msg("Failed to parse message history receiver JID") + return receiver + } + _, displayname, err := mc.getBasicUserInfo(ctx, jid) + if err != nil { + zerolog.Ctx(ctx).Err(err).Stringer("receiver_jid", jid).Msg("Failed to resolve message history receiver") + if jid.User != "" { + return jid.User + } + return receiver + } + return displayname +} + +func messageHistoryStartTime(metadata *waE2E.MessageHistoryMetadata, fallback time.Time) time.Time { + if metadata == nil { + return fallback + } + if ts := metadata.GetOldestMessageTimestamp(); ts > 0 { + return time.Unix(ts, 0).Local() + } + return fallback +} + +func (mc *MessageConverter) convertMessageHistoryShare(ctx context.Context, info *types.MessageInfo, metadata *waE2E.MessageHistoryMetadata, contextInfo *waE2E.ContextInfo) (*bridgev2.ConvertedMessagePart, *waE2E.ContextInfo) { + names := make([]string, 0, len(metadata.GetHistoryReceivers())) + for _, receiver := range metadata.GetHistoryReceivers() { + names = append(names, mc.getHistoryReceiverName(ctx, receiver)) + } + + receivers := joinNaturalNames(names) + var fallback time.Time + if info != nil { + fallback = info.Timestamp + } + startAt := messageHistoryStartTime(metadata, fallback) + body := "Message history shared." + if !startAt.IsZero() { + startTime := startAt.Format("Jan 2, 2006 at 3:04 PM") + body = fmt.Sprintf("Message history shared starting on %s.", startTime) + switch { + case info != nil && info.IsFromMe && receivers != "": + body = fmt.Sprintf("You sent %s message history that starts on %s.", receivers, startTime) + case receivers != "": + body = fmt.Sprintf("Sent %s message history that starts on %s.", receivers, startTime) + } + } else if info != nil && info.IsFromMe && receivers != "" { + body = fmt.Sprintf("You sent %s message history.", receivers) + } else if receivers != "" { + body = fmt.Sprintf("Sent %s message history.", receivers) + } + + return &bridgev2.ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: body, + }, + }, contextInfo +} + const inviteMsg = `%s
This invitation to join "%s" expires at %s. Reply to this message with %s accept to accept the invite.` const inviteMsgBroken = `%s
This invitation to join "%s" expires at %s. However, the invite message is broken or unsupported and cannot be accepted.` const GroupInviteMetaField = "fi.mau.whatsapp.invite" From 5a7217e0ffe5c6c126335fc86c5cc80be1a27eb7 Mon Sep 17 00:00:00 2001 From: Kishan Bagaria <1093313+KishanBagaria@users.noreply.github.com> Date: Fri, 27 Mar 2026 09:10:36 -0700 Subject: [PATCH 2/2] - --- pkg/msgconv/wa-misc.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/pkg/msgconv/wa-misc.go b/pkg/msgconv/wa-misc.go index 9222f78..22c014c 100644 --- a/pkg/msgconv/wa-misc.go +++ b/pkg/msgconv/wa-misc.go @@ -21,7 +21,6 @@ import ( "encoding/base64" "fmt" "html/template" - "slices" "strings" "time" @@ -74,22 +73,6 @@ func (mc *MessageConverter) convertPlaceholderMessage(ctx context.Context, rawMs } } -func joinNaturalNames(names []string) string { - names = slices.DeleteFunc(names, func(name string) bool { - return name == "" - }) - switch len(names) { - case 0: - return "" - case 1: - return names[0] - case 2: - return names[0] + " and " + names[1] - default: - return strings.Join(names[:len(names)-1], ", ") + ", and " + names[len(names)-1] - } -} - func (mc *MessageConverter) getHistoryReceiverName(ctx context.Context, receiver string) string { jid, err := types.ParseJID(receiver) if err != nil { @@ -120,10 +103,12 @@ func messageHistoryStartTime(metadata *waE2E.MessageHistoryMetadata, fallback ti func (mc *MessageConverter) convertMessageHistoryShare(ctx context.Context, info *types.MessageInfo, metadata *waE2E.MessageHistoryMetadata, contextInfo *waE2E.ContextInfo) (*bridgev2.ConvertedMessagePart, *waE2E.ContextInfo) { names := make([]string, 0, len(metadata.GetHistoryReceivers())) for _, receiver := range metadata.GetHistoryReceivers() { - names = append(names, mc.getHistoryReceiverName(ctx, receiver)) + if name := mc.getHistoryReceiverName(ctx, receiver); name != "" { + names = append(names, name) + } } - receivers := joinNaturalNames(names) + receivers := strings.Join(names, ", ") var fallback time.Time if info != nil { fallback = info.Timestamp