diff --git a/bridge/discord/discord.go b/bridge/discord/discord.go index 2fcf0abc..0ac2b50c 100644 --- a/bridge/discord/discord.go +++ b/bridge/discord/discord.go @@ -283,7 +283,7 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st // Upload a file if it exists if msg.Extra != nil { for _, rmsg := range helper.HandleExtra(msg, b.General) { - rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength) + rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength, b.GetString("MessageClipped")) if _, err := b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text); err != nil { b.Log.Errorf("Could not send message %#v: %s", rmsg, err) } @@ -294,7 +294,7 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st } } - msg.Text = helper.ClipMessage(msg.Text, MessageLength) + msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped")) msg.Text = b.replaceUserMentions(msg.Text) // Edit message diff --git a/bridge/discord/webhook.go b/bridge/discord/webhook.go index 9177db07..7b136bcb 100644 --- a/bridge/discord/webhook.go +++ b/bridge/discord/webhook.go @@ -116,7 +116,7 @@ func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (st return "", nil } - msg.Text = helper.ClipMessage(msg.Text, MessageLength) + msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped")) msg.Text = b.replaceUserMentions(msg.Text) // discord username must be [0..32] max if len(msg.Username) > 32 { diff --git a/bridge/helper/helper.go b/bridge/helper/helper.go index 0ad31457..1bdd8a40 100644 --- a/bridge/helper/helper.go +++ b/bridge/helper/helper.go @@ -82,8 +82,10 @@ func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) { // TODO: The current implementation has the inconvenient that it disregards // word boundaries when splitting but this is hard to solve without potentially // breaking formatting and other stylistic effects. -func GetSubLines(message string, maxLineLength int) []string { - const clippingMessage = " " +func GetSubLines(message string, maxLineLength int, clippingMessage string) []string { + if clippingMessage == "" { + clippingMessage = " " + } var lines []string for _, line := range strings.Split(strings.TrimSpace(message), "\n") { @@ -193,8 +195,11 @@ func RemoveEmptyNewLines(msg string) string { // ClipMessage trims a message to the specified length if it exceeds it and adds a warning // to the message in case it does so. -func ClipMessage(text string, length int) string { - const clippingMessage = " " +func ClipMessage(text string, length int, clippingMessage string) string { + if clippingMessage == "" { + clippingMessage = " " + } + if len(text) > length { text = text[:length-len(clippingMessage)] if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError { diff --git a/bridge/helper/helper_test.go b/bridge/helper/helper_test.go index 48f33b10..76e548e4 100644 --- a/bridge/helper/helper_test.go +++ b/bridge/helper/helper_test.go @@ -10,98 +10,96 @@ import ( const testLineLength = 64 -var ( - lineSplittingTestCases = map[string]struct { - input string - splitOutput []string - nonSplitOutput []string - }{ - "Short single-line message": { - input: "short", - splitOutput: []string{"short"}, - nonSplitOutput: []string{"short"}, +var lineSplittingTestCases = map[string]struct { + input string + splitOutput []string + nonSplitOutput []string +}{ + "Short single-line message": { + input: "short", + splitOutput: []string{"short"}, + nonSplitOutput: []string{"short"}, + }, + "Long single-line message": { + input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + splitOutput: []string{ + "Lorem ipsum dolor sit amet, consectetur adipis ", + "cing elit, sed do eiusmod tempor incididunt ut ", + " labore et dolore magna aliqua.", }, - "Long single-line message": { - input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - splitOutput: []string{ - "Lorem ipsum dolor sit amet, consectetur adipis ", - "cing elit, sed do eiusmod tempor incididunt ut ", - " labore et dolore magna aliqua.", - }, - nonSplitOutput: []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}, + nonSplitOutput: []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}, + }, + "Short multi-line message": { + input: "I\ncan't\nget\nno\nsatisfaction!", + splitOutput: []string{ + "I", + "can't", + "get", + "no", + "satisfaction!", }, - "Short multi-line message": { - input: "I\ncan't\nget\nno\nsatisfaction!", - splitOutput: []string{ - "I", - "can't", - "get", - "no", - "satisfaction!", - }, - nonSplitOutput: []string{ - "I", - "can't", - "get", - "no", - "satisfaction!", - }, + nonSplitOutput: []string{ + "I", + "can't", + "get", + "no", + "satisfaction!", }, - "Long multi-line message": { - input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" + - "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" + - "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" + - "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - splitOutput: []string{ - "Lorem ipsum dolor sit amet, consectetur adipis ", - "cing elit, sed do eiusmod tempor incididunt ut ", - " labore et dolore magna aliqua.", - "Ut enim ad minim veniam, quis nostrud exercita ", - "tion ullamco laboris nisi ut aliquip ex ea com ", - "modo consequat.", - "Duis aute irure dolor in reprehenderit in volu ", - "ptate velit esse cillum dolore eu fugiat nulla ", - " pariatur.", - "Excepteur sint occaecat cupidatat non proident ", - ", sunt in culpa qui officia deserunt mollit an ", - "im id est laborum.", - }, - nonSplitOutput: []string{ - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", - "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - }, + }, + "Long multi-line message": { + input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" + + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" + + "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" + + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + splitOutput: []string{ + "Lorem ipsum dolor sit amet, consectetur adipis ", + "cing elit, sed do eiusmod tempor incididunt ut ", + " labore et dolore magna aliqua.", + "Ut enim ad minim veniam, quis nostrud exercita ", + "tion ullamco laboris nisi ut aliquip ex ea com ", + "modo consequat.", + "Duis aute irure dolor in reprehenderit in volu ", + "ptate velit esse cillum dolore eu fugiat nulla ", + " pariatur.", + "Excepteur sint occaecat cupidatat non proident ", + ", sunt in culpa qui officia deserunt mollit an ", + "im id est laborum.", }, - "Message ending with new-line.": { - input: "Newline ending\n", - splitOutput: []string{"Newline ending"}, - nonSplitOutput: []string{"Newline ending"}, + nonSplitOutput: []string{ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", + "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", }, - "Long message containing UTF-8 multi-byte runes": { - input: "不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說", - splitOutput: []string{ - "不布人個我此而及單石業喜資富下 ", - "我河下日沒一我臺空達的常景便物 ", - "沒為……子大我別名解成?生賣的 ", - "全直黑,我自我結毛分洲了世當, ", - "是政福那是東;斯說", - }, - nonSplitOutput: []string{"不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說"}, + }, + "Message ending with new-line.": { + input: "Newline ending\n", + splitOutput: []string{"Newline ending"}, + nonSplitOutput: []string{"Newline ending"}, + }, + "Long message containing UTF-8 multi-byte runes": { + input: "不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說", + splitOutput: []string{ + "不布人個我此而及單石業喜資富下 ", + "我河下日沒一我臺空達的常景便物 ", + "沒為……子大我別名解成?生賣的 ", + "全直黑,我自我結毛分洲了世當, ", + "是政福那是東;斯說", }, - } -) + nonSplitOutput: []string{"不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說"}, + }, +} func TestGetSubLines(t *testing.T) { for testname, testcase := range lineSplittingTestCases { - splitLines := GetSubLines(testcase.input, testLineLength) + splitLines := GetSubLines(testcase.input, testLineLength, "") assert.Equalf(t, testcase.splitOutput, splitLines, "'%s' testcase should give expected lines with splitting.", testname) for _, splitLine := range splitLines { byteLength := len([]byte(splitLine)) assert.True(t, byteLength <= testLineLength, "Splitted line '%s' of testcase '%s' should not exceed the maximum byte-length (%d vs. %d).", splitLine, testcase, byteLength, testLineLength) } - nonSplitLines := GetSubLines(testcase.input, 0) + nonSplitLines := GetSubLines(testcase.input, 0, "") assert.Equalf(t, testcase.nonSplitOutput, nonSplitLines, "'%s' testcase should give expected lines without splitting.", testname) } } @@ -110,16 +108,19 @@ func TestConvertWebPToPNG(t *testing.T) { if os.Getenv("LOCAL_TEST") == "" { t.Skip() } + input, err := ioutil.ReadFile("test.webp") if err != nil { t.Fail() } + d := &input err = ConvertWebPToPNG(d) if err != nil { t.Fail() } - err = ioutil.WriteFile("test.png", *d, 0644) + + err = ioutil.WriteFile("test.png", *d, 0o644) // nolint:gosec if err != nil { t.Fail() } diff --git a/bridge/irc/irc.go b/bridge/irc/irc.go index 4ccdee95..e54f8030 100644 --- a/bridge/irc/irc.go +++ b/bridge/irc/irc.go @@ -167,9 +167,9 @@ func (b *Birc) Send(msg config.Message) (string, error) { } if b.GetBool("MessageSplit") { - msgLines = helper.GetSubLines(msg.Text, b.MessageLength) + msgLines = helper.GetSubLines(msg.Text, b.MessageLength, b.GetString("MessageClipped")) } else { - msgLines = helper.GetSubLines(msg.Text, 0) + msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped")) } for i := range msgLines { if len(b.Local) >= b.MessageQueue { @@ -316,12 +316,16 @@ func (b *Birc) endNames(client *girc.Client, event girc.Event) { sort.Strings(b.names[channel]) maxNamesPerPost := (300 / b.nicksPerRow()) * b.nicksPerRow() for len(b.names[channel]) > maxNamesPerPost { - b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost]), - Channel: channel, Account: b.Account} + b.Remote <- config.Message{ + Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost]), + Channel: channel, Account: b.Account, + } b.names[channel] = b.names[channel][maxNamesPerPost:] } - b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel]), - Channel: channel, Account: b.Account} + b.Remote <- config.Message{ + Username: b.Nick, Text: b.formatnicks(b.names[channel]), + Channel: channel, Account: b.Account, + } b.names[channel] = nil b.i.Handlers.Clear(girc.RPL_NAMREPLY) b.i.Handlers.Clear(girc.RPL_ENDOFNAMES) diff --git a/bridge/mumble/mumble.go b/bridge/mumble/mumble.go index 2281d1c2..d678e0fb 100644 --- a/bridge/mumble/mumble.go +++ b/bridge/mumble/mumble.go @@ -248,9 +248,9 @@ func (b *Bmumble) processMessage(msg *config.Message) { // If there is a maximum message length, split and truncate the lines var msgLines []string if maxLength := b.serverConfig.MaximumMessageLength; maxLength != nil { - msgLines = helper.GetSubLines(msg.Text, *maxLength-len(msg.Username)) + msgLines = helper.GetSubLines(msg.Text, *maxLength-len(msg.Username), b.GetString("MessageClipped")) } else { - msgLines = helper.GetSubLines(msg.Text, 0) + msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped")) } // Send the individual lindes for i := range msgLines { diff --git a/bridge/slack/slack.go b/bridge/slack/slack.go index 37ddd853..457312cd 100644 --- a/bridge/slack/slack.go +++ b/bridge/slack/slack.go @@ -195,7 +195,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) { b.Log.Debugf("=> Receiving %#v", msg) } - msg.Text = helper.ClipMessage(msg.Text, messageLength) + msg.Text = helper.ClipMessage(msg.Text, messageLength, b.GetString("MessageClipped")) msg.Text = b.replaceCodeFence(msg.Text) // Make a action /me of the message diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample index 2819b287..a1b8a5fc 100644 --- a/matterbridge.toml.sample +++ b/matterbridge.toml.sample @@ -76,20 +76,24 @@ MessageDelay=1300 #Maximum amount of messages to hold in queue. If queue is full #messages will be dropped. -# will be add to the message that fills the queue. +# will be add to the message that fills the queue. #OPTIONAL (default 30) MessageQueue=30 #Maximum length of message sent to irc server. If it exceeds -# will be add to the message. +# will be add to the message. #OPTIONAL (default 400) MessageLength=400 -#Split messages on MessageLength instead of showing the +#Split messages on MessageLength instead of showing the #WARNING: this could lead to flooding #OPTIONAL (default false) MessageSplit=false +#Message to show when a message is too big +#Default "" +MessageClipped="" + #Delay in seconds to rejoin a channel when kicked #OPTIONAL (default 0) RejoinDelay=0 @@ -826,6 +830,10 @@ PreserveThreading=false #OPTIONAL (default false) ShowUserTyping=false +#Message to show when a message is too big +#Default "" +MessageClipped="" + ################################################################### #discord section ################################################################### @@ -961,6 +969,10 @@ ShowTopicChange=false # Supported from the following bridges: slack SyncTopic=false +#Message to show when a message is too big +#Default "" +MessageClipped="" + ################################################################### #telegram section ################################################################### @@ -1435,9 +1447,7 @@ StripNick=false ShowTopicChange=false ################################################################### -# # NCTalk (Nextcloud Talk) -# ################################################################### [nctalk.bridge] @@ -1460,9 +1470,7 @@ Password = "talkuserpass" GuestSuffix = " (Guest)" ################################################################### -# # Mumble -# ################################################################### [mumble.bridge] @@ -1505,9 +1513,14 @@ TLSCACertificate=mumble-ca.crt # OPTIONAL (default false) SkipTLSVerify=false +#Message to show when a message is too big +#Default "" +MessageClipped="" + ################################################################### #VK ################################################################### +# [vk.myvk] #Group access token #See https://vk.com/dev/bots_docs @@ -1518,9 +1531,7 @@ Token="Yourtokenhere" GroupID=123456789 ################################################################### -# # WhatsApp -# ################################################################### [whatsapp.bridge] @@ -1547,9 +1558,7 @@ Label="Organization" ################################################################### -# # zulip -# ################################################################### [zulip]