From ac2f7da59d79ea5b03414e3f4289417668ca6bb4 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 16 Aug 2024 08:59:32 +0100 Subject: [PATCH 1/4] discord: put attachment URLs into Extra["file"] previously, the urls were just appended to the message content. i couldn't find any other assignments directly to Extra["file"] anywhere in the codebase, so maybe there's a better way to do this. --- bridge/discord/handlers.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bridge/discord/handlers.go b/bridge/discord/handlers.go index 34cef55480..851698f106 100644 --- a/bridge/discord/handlers.go +++ b/bridge/discord/handlers.go @@ -98,15 +98,19 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat return } + + rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID, Extra: make(map[string][]interface{}, 0)} + // add the url of the attachments to content if len(m.Attachments) > 0 { for _, attach := range m.Attachments { - m.Content = m.Content + "\n" + attach.URL + rmsg.Extra["file"] = append(rmsg.Extra["file"], config.FileInfo { + URL: attach.URL, + }) + // m.Content = m.Content + "\n" + attach.URL } } - rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID} - b.Log.Debugf("== Receiving event %#v", m.Message) if m.Content != "" { @@ -139,7 +143,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat } // no empty messages - if rmsg.Text == "" { + if rmsg.Text == "" && len(rmsg.Extra["file"]) == 0 { return } From e168a89632bff7b75fa12085367e28ea2e0a04c9 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 16 Aug 2024 09:02:07 +0100 Subject: [PATCH 2/4] xmpp: set body text to attachment URL in XEP-0066 OOB messages many clients will only display files inline if the message body itself exactly matches the attachment URL. see https://docs.modernxmpp.org/client/protocol/#communicating-the-url --- bridge/xmpp/xmpp.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/bridge/xmpp/xmpp.go b/bridge/xmpp/xmpp.go index cf58a2fc47..54649324b4 100644 --- a/bridge/xmpp/xmpp.go +++ b/bridge/xmpp/xmpp.go @@ -362,20 +362,14 @@ func (b *Bxmpp) replaceAction(text string) (string, bool) { // handleUploadFile handles native upload of files func (b *Bxmpp) handleUploadFile(msg *config.Message) error { - var urlDesc string - for _, file := range msg.Extra["file"] { fileInfo := file.(config.FileInfo) if fileInfo.Comment != "" { - msg.Text += fileInfo.Comment + ": " - } - if fileInfo.URL != "" { - msg.Text = fileInfo.URL - if fileInfo.Comment != "" { - msg.Text = fileInfo.Comment + ": " + fileInfo.URL - urlDesc = fileInfo.Comment - } + msg.Text += fileInfo.Comment } + + // this is sent even if Text is empty, + // so that you can tell who sent the message if _, err := b.xc.Send(xmpp.Chat{ Type: "groupchat", Remote: msg.Channel + "@" + b.GetString("Muc"), @@ -385,13 +379,14 @@ func (b *Bxmpp) handleUploadFile(msg *config.Message) error { } if fileInfo.URL != "" { - if _, err := b.xc.SendOOB(xmpp.Chat{ + if _, err := b.xc.Send(xmpp.Chat{ Type: "groupchat", Remote: msg.Channel + "@" + b.GetString("Muc"), + Text: fileInfo.URL, Ooburl: fileInfo.URL, - Oobdesc: urlDesc, }); err != nil { b.Log.WithError(err).Warn("Failed to send share URL.") + return err } } } From 707a74ba0e518be098d7111816329a4c5911fa4e Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 16 Aug 2024 10:04:12 +0100 Subject: [PATCH 3/4] discord: support sending files with just a URL previously, the code assumed each file had a Data, and crashed if this was not present. now, we detect this condition, and send the URL instead. the discord client will display URLs in a message of their own as inline embeds, without any special behavior needed on our part. this commit makes the same changes to the webhook and non-webhook code. --- bridge/discord/discord.go | 55 +++++++++++++++++++++++--------- bridge/discord/webhook.go | 66 ++++++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 33 deletions(-) diff --git a/bridge/discord/discord.go b/bridge/discord/discord.go index 3f99da0cee..2c1a69d228 100644 --- a/bridge/discord/discord.go +++ b/bridge/discord/discord.go @@ -380,26 +380,51 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st // handleUploadFile handles native upload of files func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) { for _, f := range msg.Extra["file"] { + var err error fi := f.(config.FileInfo) - file := discordgo.File{ - Name: fi.Name, - ContentType: "", - Reader: bytes.NewReader(*fi.Data), - } - m := discordgo.MessageSend{ - Content: msg.Username + fi.Comment, - Files: []*discordgo.File{&file}, - AllowedMentions: b.getAllowedMentions(), + + if fi.URL != "" { + err = b.handleUploadFileFromURL(msg, channelID, &fi) + } else if fi.Data != nil { + err = b.handleUploadFileFromData(msg, channelID, &fi) + } else { + b.Log.Errorf("Attachment %#v for message %#v had neither Data nor URL", fi, msg) } - res, err := b.c.ChannelMessageSendComplex(channelID, &m) + if err != nil { - return "", fmt.Errorf("file upload failed: %s", err) + b.Log.Errorf("Could not send attachment %#v for message %#v: %s", fi, msg, err) + return "", err } - - // link file_upload_nativeID (file ID from the original bridge) to our upload id - // so that we can remove this later when it eg needs to be deleted - b.cache.Add(cFileUpload+fi.NativeID, res.ID) } return "", nil } + +func (b *Bdiscord) handleUploadFileFromData(msg *config.Message, channelID string, fi *config.FileInfo) error { + file := discordgo.File{ + Name: fi.Name, + ContentType: "", + Reader: bytes.NewReader(*fi.Data), + } + m := discordgo.MessageSend{ + Content: msg.Username + fi.Comment, + Files: []*discordgo.File{&file}, + AllowedMentions: b.getAllowedMentions(), + } + res, err := b.c.ChannelMessageSendComplex(channelID, &m) + if err != nil { + return fmt.Errorf("file upload failed: %s", err) + } + // link file_upload_nativeID (file ID from the original bridge) to our upload id + // so that we can remove this later when it eg needs to be deleted + b.cache.Add(cFileUpload+fi.NativeID, res.ID) + return nil +} + +func (b *Bdiscord) handleUploadFileFromURL(msg *config.Message, channelID string, fi *config.FileInfo) error { + _, err := b.c.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{ + Content: fi.URL, + AllowedMentions: b.getAllowedMentions(), + }) + return err +} diff --git a/bridge/discord/webhook.go b/bridge/discord/webhook.go index ef129d4c07..2e7227ebf7 100644 --- a/bridge/discord/webhook.go +++ b/bridge/discord/webhook.go @@ -69,33 +69,63 @@ func (b *Bdiscord) webhookSendTextOnly(msg *config.Message, channelID string) (s func (b *Bdiscord) webhookSendFilesOnly(msg *config.Message, channelID string) error { for _, f := range msg.Extra["file"] { fi := f.(config.FileInfo) //nolint:forcetypeassert - file := discordgo.File{ - Name: fi.Name, - ContentType: "", - Reader: bytes.NewReader(*fi.Data), + var err error + + if fi.URL != "" { + err = b.webhookSendFileFromURL(msg, channelID, &fi) + } else if fi.Data != nil { + err = b.webhookSendFileFromData(msg, channelID, &fi) + } else { + b.Log.Errorf("Attachment %#v for message %#v had neither Data nor URL", fi, msg) } - content := fi.Comment - // Cannot use the resulting ID for any edits anyway, so throw it away. - // This has to be re-enabled when we implement message deletion. - _, err := b.transmitter.Send( - channelID, - &discordgo.WebhookParams{ - Username: msg.Username, - AvatarURL: msg.Avatar, - Files: []*discordgo.File{&file}, - Content: content, - AllowedMentions: b.getAllowedMentions(), - }, - ) if err != nil { - b.Log.Errorf("Could not send file %#v for message %#v: %s", file, msg, err) + b.Log.Errorf("Could not send attachment %#v for message %#v: %s", fi, msg, err) return err } } + return nil } +func (b *Bdiscord) webhookSendFileFromData(msg *config.Message, channelID string, fi *config.FileInfo) error { + file := discordgo.File{ + Name: fi.Name, + ContentType: "", + Reader: bytes.NewReader(*fi.Data), + } + content := fi.Comment + + // Cannot use the resulting ID for any edits anyway, so throw it away. + // This has to be re-enabled when we implement message deletion. + _, err := b.transmitter.Send( + channelID, + &discordgo.WebhookParams{ + Username: msg.Username, + AvatarURL: msg.Avatar, + Files: []*discordgo.File{&file}, + Content: content, + AllowedMentions: b.getAllowedMentions(), + }, + ) + return err +} + +func (b *Bdiscord) webhookSendFileFromURL(msg *config.Message, channelID string, fi *config.FileInfo) error { + // discord client will display any file url as an inline embed, + // without us having to do anything special. + _, err := b.transmitter.Send( + channelID, + &discordgo.WebhookParams{ + Content: fi.URL, + Username: msg.Username, + AvatarURL: msg.Avatar, + AllowedMentions: b.getAllowedMentions(), + }, + ) + return err +} + // webhookSend send one or more message via webhook, taking care of file // uploads (from slack, telegram or mattermost). // Returns messageID and error. From ce93d9024ba98d8333f4b74eef347105ad78a89e Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 16 Aug 2024 11:48:39 +0100 Subject: [PATCH 4/4] irc: don't drop message body when sending attachment URLs --- bridge/irc/handlers.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/bridge/irc/handlers.go b/bridge/irc/handlers.go index cb2cc85581..19d1b20fad 100644 --- a/bridge/irc/handlers.go +++ b/bridge/irc/handlers.go @@ -50,18 +50,26 @@ func (b *Birc) handleFiles(msg *config.Message) bool { if len(msg.Extra["file"]) == 0 { return false } + + if msg.Text != "" { + b.Local <- config.Message{ + Text: msg.Text, + Username: msg.Username, + Channel: msg.Channel, + Event: msg.Event, + } + } + for _, f := range msg.Extra["file"] { fi := f.(config.FileInfo) + var text = "" if fi.Comment != "" { - msg.Text += fi.Comment + " : " + text += fi.Comment + " : " } if fi.URL != "" { - msg.Text = fi.URL - if fi.Comment != "" { - msg.Text = fi.Comment + " : " + fi.URL - } + text += fi.URL } - b.Local <- config.Message{Text: msg.Text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event} + b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event} } return true }