|
|
|
@ -268,6 +268,8 @@ type Portal struct {
|
|
|
|
|
|
|
|
|
|
mediaErrorCache map[types.MessageID]*FailedMediaMeta
|
|
|
|
|
|
|
|
|
|
currentlySleepingToDelete sync.Map
|
|
|
|
|
|
|
|
|
|
relayUser *User
|
|
|
|
|
parentPortal *Portal
|
|
|
|
|
}
|
|
|
|
@ -613,13 +615,8 @@ func (portal *Portal) UpdateGroupDisappearingMessages(sender *types.JID, timesta
|
|
|
|
|
func (portal *Portal) formatDisappearingMessageNotice() string {
|
|
|
|
|
if portal.ExpirationTime == 0 {
|
|
|
|
|
return "Turned off disappearing messages"
|
|
|
|
|
} else {
|
|
|
|
|
msg := fmt.Sprintf("Set the disappearing message timer to %s", formatDuration(time.Duration(portal.ExpirationTime)*time.Second))
|
|
|
|
|
if !portal.bridge.Config.Bridge.DisappearingMessagesInGroups && portal.IsGroupChat() {
|
|
|
|
|
msg += ". However, this bridge is not configured to disappear messages in group chats."
|
|
|
|
|
}
|
|
|
|
|
return msg
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("Set the disappearing message timer to %s", formatDuration(time.Duration(portal.ExpirationTime)*time.Second))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UndecryptableMessageNotice = "Decrypting message from WhatsApp failed, waiting for sender to re-send... " +
|
|
|
|
@ -758,7 +755,7 @@ func (portal *Portal) handleMessage(source *User, evt *events.Message) {
|
|
|
|
|
var eventID id.EventID
|
|
|
|
|
var lastEventID id.EventID
|
|
|
|
|
if existingMsg != nil {
|
|
|
|
|
portal.MarkDisappearing(nil, existingMsg.MXID, converted.ExpiresIn, false)
|
|
|
|
|
portal.MarkDisappearing(nil, existingMsg.MXID, converted.ExpiresIn, evt.Info.Timestamp)
|
|
|
|
|
converted.Content.SetEdit(existingMsg.MXID)
|
|
|
|
|
} else if converted.ReplyTo != nil {
|
|
|
|
|
portal.SetReply(converted.Content, converted.ReplyTo, false)
|
|
|
|
@ -773,7 +770,7 @@ func (portal *Portal) handleMessage(source *User, evt *events.Message) {
|
|
|
|
|
portal.log.Errorfln("Failed to send %s to Matrix: %v", msgID, err)
|
|
|
|
|
} else {
|
|
|
|
|
if editTargetMsg == nil {
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, false)
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, evt.Info.Timestamp)
|
|
|
|
|
}
|
|
|
|
|
eventID = resp.EventID
|
|
|
|
|
lastEventID = eventID
|
|
|
|
@ -784,7 +781,7 @@ func (portal *Portal) handleMessage(source *User, evt *events.Message) {
|
|
|
|
|
if err != nil {
|
|
|
|
|
portal.log.Errorfln("Failed to send caption of %s to Matrix: %v", msgID, err)
|
|
|
|
|
} else {
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, false)
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, evt.Info.Timestamp)
|
|
|
|
|
lastEventID = resp.EventID
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -794,7 +791,7 @@ func (portal *Portal) handleMessage(source *User, evt *events.Message) {
|
|
|
|
|
if err != nil {
|
|
|
|
|
portal.log.Errorfln("Failed to send sub-event %d of %s to Matrix: %v", index+1, msgID, err)
|
|
|
|
|
} else {
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, false)
|
|
|
|
|
portal.MarkDisappearing(nil, resp.EventID, converted.ExpiresIn, evt.Info.Timestamp)
|
|
|
|
|
lastEventID = resp.EventID
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2049,7 +2046,7 @@ type ConvertedMessage struct {
|
|
|
|
|
MultiEvent []*event.MessageEventContent
|
|
|
|
|
|
|
|
|
|
ReplyTo *ReplyInfo
|
|
|
|
|
ExpiresIn uint32
|
|
|
|
|
ExpiresIn time.Duration
|
|
|
|
|
Error database.MessageErrorType
|
|
|
|
|
MediaKey []byte
|
|
|
|
|
}
|
|
|
|
@ -2082,7 +2079,7 @@ func (portal *Portal) convertTextMessage(intent *appservice.IntentAPI, source *U
|
|
|
|
|
|
|
|
|
|
contextInfo := msg.GetExtendedTextMessage().GetContextInfo()
|
|
|
|
|
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, content, contextInfo.GetMentionedJid(), false, false)
|
|
|
|
|
expiresIn := contextInfo.GetExpiration()
|
|
|
|
|
expiresIn := time.Duration(contextInfo.GetExpiration()) * time.Second
|
|
|
|
|
extraAttrs := map[string]interface{}{}
|
|
|
|
|
extraAttrs["com.beeper.linkpreviews"] = portal.convertURLPreviewToBeeper(intent, source, msg.GetExtendedTextMessage())
|
|
|
|
|
|
|
|
|
@ -2105,7 +2102,7 @@ func (portal *Portal) convertTemplateMessage(intent *appservice.IntentAPI, sourc
|
|
|
|
|
MsgType: event.MsgText,
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(tplMsg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: tplMsg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(tplMsg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tpl := tplMsg.GetHydratedTemplate()
|
|
|
|
@ -2182,7 +2179,7 @@ func (portal *Portal) convertTemplateButtonReplyMessage(intent *appservice.Inten
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2195,7 +2192,7 @@ func (portal *Portal) convertListMessage(intent *appservice.IntentAPI, source *U
|
|
|
|
|
MsgType: event.MsgText,
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
body := msg.GetDescription()
|
|
|
|
|
if msg.GetTitle() != "" {
|
|
|
|
@ -2262,7 +2259,7 @@ func (portal *Portal) convertListResponseMessage(intent *appservice.IntentAPI, m
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2405,7 +2402,7 @@ func (portal *Portal) convertPollCreationMessage(intent *appservice.IntentAPI, m
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2422,7 +2419,7 @@ func (portal *Portal) convertLiveLocationMessage(intent *appservice.IntentAPI, m
|
|
|
|
|
Type: event.EventMessage,
|
|
|
|
|
Content: content,
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2474,7 +2471,7 @@ func (portal *Portal) convertLocationMessage(intent *appservice.IntentAPI, msg *
|
|
|
|
|
Type: event.EventMessage,
|
|
|
|
|
Content: content,
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2516,7 +2513,7 @@ func (portal *Portal) convertGroupInviteMessage(intent *appservice.IntentAPI, in
|
|
|
|
|
Content: content,
|
|
|
|
|
Extra: extraAttrs,
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2552,7 +2549,7 @@ func (portal *Portal) convertContactMessage(intent *appservice.IntentAPI, msg *w
|
|
|
|
|
Type: event.EventMessage,
|
|
|
|
|
Content: content,
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2576,7 +2573,7 @@ func (portal *Portal) convertContactsArrayMessage(intent *appservice.IntentAPI,
|
|
|
|
|
Body: fmt.Sprintf("Sent %s", name),
|
|
|
|
|
},
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
MultiEvent: contacts,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2935,7 +2932,7 @@ func (portal *Portal) convertMediaMessageContent(intent *appservice.IntentAPI, m
|
|
|
|
|
Content: content,
|
|
|
|
|
Caption: captionContent,
|
|
|
|
|
ReplyTo: GetReply(msg.GetContextInfo()),
|
|
|
|
|
ExpiresIn: msg.GetContextInfo().GetExpiration(),
|
|
|
|
|
ExpiresIn: time.Duration(msg.GetContextInfo().GetExpiration()) * time.Second,
|
|
|
|
|
Extra: extraContent,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -3725,6 +3722,7 @@ func (portal *Portal) generateContextInfo(relatesTo *event.RelatesTo) *waProto.C
|
|
|
|
|
|
|
|
|
|
type extraConvertMeta struct {
|
|
|
|
|
PollOptions map[[32]byte]string
|
|
|
|
|
EditRootMsg *database.Message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, evt *event.Event) (*waProto.Message, *User, *extraConvertMeta, error) {
|
|
|
|
@ -3737,12 +3735,14 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, sender, nil, fmt.Errorf("%w %T", errUnexpectedParsedContentType, evt.Content.Parsed)
|
|
|
|
|
}
|
|
|
|
|
extraMeta := &extraConvertMeta{}
|
|
|
|
|
var editRootMsg *database.Message
|
|
|
|
|
if editEventID := content.RelatesTo.GetReplaceID(); editEventID != "" && portal.bridge.Config.Bridge.SendWhatsAppEdits {
|
|
|
|
|
editRootMsg = portal.bridge.DB.Message.GetByMXID(editEventID)
|
|
|
|
|
if editRootMsg == nil || editRootMsg.Type != database.MsgNormal || editRootMsg.IsFakeJID() || editRootMsg.Sender.User != sender.JID.User {
|
|
|
|
|
return nil, sender, nil, fmt.Errorf("edit rejected") // TODO more specific error message
|
|
|
|
|
return nil, sender, extraMeta, fmt.Errorf("edit rejected") // TODO more specific error message
|
|
|
|
|
}
|
|
|
|
|
extraMeta.EditRootMsg = editRootMsg
|
|
|
|
|
if content.NewContent != nil {
|
|
|
|
|
content = content.NewContent
|
|
|
|
|
}
|
|
|
|
@ -3753,7 +3753,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
relaybotFormatted := false
|
|
|
|
|
if !sender.IsLoggedIn() || (portal.IsPrivateChat() && sender.JID.User != portal.Key.Receiver.User) {
|
|
|
|
|
if !portal.HasRelaybot() {
|
|
|
|
|
return nil, sender, nil, errUserNotLoggedIn
|
|
|
|
|
return nil, sender, extraMeta, errUserNotLoggedIn
|
|
|
|
|
}
|
|
|
|
|
relaybotFormatted = portal.addRelaybotFormat(sender, content)
|
|
|
|
|
sender = portal.GetRelayUser()
|
|
|
|
@ -3774,7 +3774,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MsgText, event.MsgEmote, event.MsgNotice:
|
|
|
|
|
text := content.Body
|
|
|
|
|
if content.MsgType == event.MsgNotice && !portal.bridge.Config.Bridge.BridgeNotices {
|
|
|
|
|
return nil, sender, nil, errMNoticeDisabled
|
|
|
|
|
return nil, sender, extraMeta, errMNoticeDisabled
|
|
|
|
|
}
|
|
|
|
|
if content.Format == event.FormatHTML {
|
|
|
|
|
text, ctxInfo.MentionedJid = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
|
|
|
|
@ -3788,7 +3788,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
}
|
|
|
|
|
hasPreview := portal.convertURLPreviewToWhatsApp(ctx, sender, evt, msg.ExtendedTextMessage)
|
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
|
return nil, nil, nil, ctx.Err()
|
|
|
|
|
return nil, sender, extraMeta, ctx.Err()
|
|
|
|
|
}
|
|
|
|
|
if ctxInfo.StanzaId == nil && ctxInfo.MentionedJid == nil && ctxInfo.Expiration == nil && !hasPreview {
|
|
|
|
|
// No need for extended message
|
|
|
|
@ -3798,7 +3798,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MsgImage:
|
|
|
|
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaImage)
|
|
|
|
|
if media == nil {
|
|
|
|
|
return nil, sender, nil, err
|
|
|
|
|
return nil, sender, extraMeta, err
|
|
|
|
|
}
|
|
|
|
|
ctxInfo.MentionedJid = media.MentionedJIDs
|
|
|
|
|
msg.ImageMessage = &waProto.ImageMessage{
|
|
|
|
@ -3815,7 +3815,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MessageType(event.EventSticker.Type):
|
|
|
|
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaImage)
|
|
|
|
|
if media == nil {
|
|
|
|
|
return nil, sender, nil, err
|
|
|
|
|
return nil, sender, extraMeta, err
|
|
|
|
|
}
|
|
|
|
|
ctxInfo.MentionedJid = media.MentionedJIDs
|
|
|
|
|
msg.StickerMessage = &waProto.StickerMessage{
|
|
|
|
@ -3832,7 +3832,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
gifPlayback := content.GetInfo().MimeType == "image/gif"
|
|
|
|
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaVideo)
|
|
|
|
|
if media == nil {
|
|
|
|
|
return nil, sender, nil, err
|
|
|
|
|
return nil, sender, extraMeta, err
|
|
|
|
|
}
|
|
|
|
|
duration := uint32(content.GetInfo().Duration / 1000)
|
|
|
|
|
ctxInfo.MentionedJid = media.MentionedJIDs
|
|
|
|
@ -3852,7 +3852,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MsgAudio:
|
|
|
|
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaAudio)
|
|
|
|
|
if media == nil {
|
|
|
|
|
return nil, sender, nil, err
|
|
|
|
|
return nil, sender, extraMeta, err
|
|
|
|
|
}
|
|
|
|
|
duration := uint32(content.GetInfo().Duration / 1000)
|
|
|
|
|
msg.AudioMessage = &waProto.AudioMessage{
|
|
|
|
@ -3875,7 +3875,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MsgFile:
|
|
|
|
|
media, err := portal.preprocessMatrixMedia(ctx, sender, relaybotFormatted, content, evt.ID, whatsmeow.MediaDocument)
|
|
|
|
|
if media == nil {
|
|
|
|
|
return nil, sender, nil, err
|
|
|
|
|
return nil, sender, extraMeta, err
|
|
|
|
|
}
|
|
|
|
|
msg.DocumentMessage = &waProto.DocumentMessage{
|
|
|
|
|
ContextInfo: ctxInfo,
|
|
|
|
@ -3901,7 +3901,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
case event.MsgLocation:
|
|
|
|
|
lat, long, err := parseGeoURI(content.GeoURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, sender, nil, fmt.Errorf("%w: %v", errInvalidGeoURI, err)
|
|
|
|
|
return nil, sender, extraMeta, fmt.Errorf("%w: %v", errInvalidGeoURI, err)
|
|
|
|
|
}
|
|
|
|
|
msg.LocationMessage = &waProto.LocationMessage{
|
|
|
|
|
DegreesLatitude: &lat,
|
|
|
|
@ -3910,7 +3910,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
ContextInfo: ctxInfo,
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nil, sender, nil, fmt.Errorf("%w %q", errUnknownMsgType, content.MsgType)
|
|
|
|
|
return nil, sender, extraMeta, fmt.Errorf("%w %q", errUnknownMsgType, content.MsgType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if editRootMsg != nil {
|
|
|
|
@ -3932,7 +3932,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return msg, sender, nil, nil
|
|
|
|
|
return msg, sender, extraMeta, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (portal *Portal) generateMessageInfo(sender *User) *types.MessageInfo {
|
|
|
|
@ -4022,7 +4022,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing
|
|
|
|
|
if msg.PollCreationMessage != nil || msg.PollCreationMessageV2 != nil {
|
|
|
|
|
dbMsgType = database.MsgMatrixPoll
|
|
|
|
|
} else if msg.EditedMessage == nil {
|
|
|
|
|
portal.MarkDisappearing(nil, origEvtID, portal.ExpirationTime, true)
|
|
|
|
|
portal.MarkDisappearing(nil, origEvtID, time.Duration(portal.ExpirationTime)*time.Second, time.Now())
|
|
|
|
|
} else {
|
|
|
|
|
dbMsgType = database.MsgEdit
|
|
|
|
|
}
|
|
|
|
|