forked from lug/matterbridge
Compare commits
42 Commits
v0.11.0-be
...
v0.13.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7811c330db | ||
|
|
9bcd131e66 | ||
|
|
c791423dd5 | ||
|
|
80bdf38388 | ||
|
|
9d9cb32f4e | ||
|
|
87229bab13 | ||
|
|
f065e9e4d5 | ||
|
|
3812693111 | ||
|
|
dd3c572256 | ||
|
|
c5dfe40326 | ||
|
|
ef278301e3 | ||
|
|
2888fd64b0 | ||
|
|
27c0f37e49 | ||
|
|
0774f6a5e7 | ||
|
|
4036d4459b | ||
|
|
ee643de5b6 | ||
|
|
8c7549a09e | ||
|
|
7a16146304 | ||
|
|
3d3809a21b | ||
|
|
29465397dd | ||
|
|
d300bb1735 | ||
|
|
2e703472f1 | ||
|
|
8fede90b9e | ||
|
|
d128f157c4 | ||
|
|
4fcedabfd0 | ||
|
|
246c8e4f74 | ||
|
|
4d2207aba7 | ||
|
|
17b8b86d68 | ||
|
|
fdb57230a3 | ||
|
|
7469732bbc | ||
|
|
d1dd6c3440 | ||
|
|
02612c0061 | ||
|
|
a4db63a773 | ||
|
|
035c2b906a | ||
|
|
6ea8be5749 | ||
|
|
36024d5439 | ||
|
|
8d52c98373 | ||
|
|
b4a4eb0057 | ||
|
|
b469c8ddbd | ||
|
|
eee0036c7f | ||
|
|
89c66b9430 | ||
|
|
bd38319d83 |
@@ -28,7 +28,7 @@ Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, R
|
|||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
Accounts to one of the supported bridges
|
Accounts to one of the supported bridges
|
||||||
* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.7.x
|
* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.9.x
|
||||||
* [IRC](http://www.mirc.com/servers.html)
|
* [IRC](http://www.mirc.com/servers.html)
|
||||||
* [XMPP](https://jabber.org)
|
* [XMPP](https://jabber.org)
|
||||||
* [Gitter](https://gitter.im)
|
* [Gitter](https://gitter.im)
|
||||||
@@ -42,7 +42,7 @@ Accounts to one of the supported bridges
|
|||||||
# Installing
|
# Installing
|
||||||
## Binaries
|
## Binaries
|
||||||
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
|
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
|
||||||
* Latest release [v0.10.3](https://github.com/42wim/matterbridge/releases/latest)
|
* Latest stable release [v0.13.0](https://github.com/42wim/matterbridge/releases/latest)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
Go 1.6+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
|
Go 1.6+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
|
|||||||
log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
|
log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
|
||||||
mychannel = mychannel + " " + channel.Options.Key
|
mychannel = mychannel + " " + channel.Options.Key
|
||||||
}
|
}
|
||||||
err := b.JoinChannel(channel.Name)
|
err := b.JoinChannel(mychannel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EVENT_JOIN_LEAVE = "join_leave"
|
EVENT_JOIN_LEAVE = "join_leave"
|
||||||
EVENT_FAILURE = "failure"
|
EVENT_FAILURE = "failure"
|
||||||
|
EVENT_REJOIN_CHANNELS = "rejoin_channels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
@@ -38,6 +39,8 @@ type ChannelInfo struct {
|
|||||||
type Protocol struct {
|
type Protocol struct {
|
||||||
BindAddress string // mattermost, slack
|
BindAddress string // mattermost, slack
|
||||||
Buffer int // api
|
Buffer int // api
|
||||||
|
EditSuffix string // mattermost, slack, discord, telegram, gitter
|
||||||
|
EditDisable bool // mattermost, slack, discord, telegram, gitter
|
||||||
IconURL string // mattermost, slack
|
IconURL string // mattermost, slack
|
||||||
IgnoreNicks string // all protocols
|
IgnoreNicks string // all protocols
|
||||||
Jid string // xmpp
|
Jid string // xmpp
|
||||||
@@ -49,12 +52,14 @@ type Protocol struct {
|
|||||||
NickServNick string // IRC
|
NickServNick string // IRC
|
||||||
NickServPassword string // IRC
|
NickServPassword string // IRC
|
||||||
NicksPerRow int // mattermost, slack
|
NicksPerRow int // mattermost, slack
|
||||||
|
NoHomeServerSuffix bool // matrix
|
||||||
NoTLS bool // mattermost
|
NoTLS bool // mattermost
|
||||||
Password string // IRC,mattermost,XMPP,matrix
|
Password string // IRC,mattermost,XMPP,matrix
|
||||||
PrefixMessagesWithNick bool // mattemost, slack
|
PrefixMessagesWithNick bool // mattemost, slack
|
||||||
Protocol string //all protocols
|
Protocol string //all protocols
|
||||||
MessageQueue int // IRC, size of message queue for flood control
|
MessageQueue int // IRC, size of message queue for flood control
|
||||||
MessageDelay int // IRC, time in millisecond to wait between messages
|
MessageDelay int // IRC, time in millisecond to wait between messages
|
||||||
|
MessageLength int // IRC, max length of a message allowed
|
||||||
MessageFormat string // telegram
|
MessageFormat string // telegram
|
||||||
RemoteNickFormat string // all protocols
|
RemoteNickFormat string // all protocols
|
||||||
Server string // IRC,mattermost,XMPP,discord
|
Server string // IRC,mattermost,XMPP,discord
|
||||||
@@ -66,6 +71,7 @@ type Protocol struct {
|
|||||||
UseAPI bool // mattermost, slack
|
UseAPI bool // mattermost, slack
|
||||||
UseSASL bool // IRC
|
UseSASL bool // IRC
|
||||||
UseTLS bool // IRC
|
UseTLS bool // IRC
|
||||||
|
UseFirstName bool // telegram
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelOptions struct {
|
type ChannelOptions struct {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -51,6 +52,7 @@ func (b *bdiscord) Connect() error {
|
|||||||
flog.Info("Connection succeeded")
|
flog.Info("Connection succeeded")
|
||||||
b.c.AddHandler(b.messageCreate)
|
b.c.AddHandler(b.messageCreate)
|
||||||
b.c.AddHandler(b.memberUpdate)
|
b.c.AddHandler(b.memberUpdate)
|
||||||
|
b.c.AddHandler(b.messageUpdate)
|
||||||
err = b.c.Open()
|
err = b.c.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.Debugf("%#v", err)
|
flog.Debugf("%#v", err)
|
||||||
@@ -103,6 +105,18 @@ func (b *bdiscord) Send(msg config.Message) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
|
||||||
|
if b.Config.EditDisable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// only when message is actually edited
|
||||||
|
if m.Message.EditedTimestamp != "" {
|
||||||
|
flog.Debugf("Sending edit message")
|
||||||
|
m.Content = m.Content + b.Config.EditSuffix
|
||||||
|
b.messageCreate(s, (*discordgo.MessageCreate)(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
// not relay our own messages
|
// not relay our own messages
|
||||||
if m.Author.Username == b.Nick {
|
if m.Author.Username == b.Nick {
|
||||||
@@ -125,6 +139,8 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
|
|||||||
if len(m.MentionRoles) > 0 {
|
if len(m.MentionRoles) > 0 {
|
||||||
m.Message.Content = b.replaceRoleMentions(m.Message.Content)
|
m.Message.Content = b.replaceRoleMentions(m.Message.Content)
|
||||||
}
|
}
|
||||||
|
m.Message.Content = b.stripCustomoji(m.Message.Content)
|
||||||
|
m.Message.Content = b.replaceChannelMentions(m.Message.Content)
|
||||||
b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
|
b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
|
||||||
Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
|
Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
|
||||||
}
|
}
|
||||||
@@ -143,12 +159,14 @@ func (b *bdiscord) getNick(user *discordgo.User) string {
|
|||||||
b.Lock()
|
b.Lock()
|
||||||
defer b.Unlock()
|
defer b.Unlock()
|
||||||
if _, ok := b.userMemberMap[user.ID]; ok {
|
if _, ok := b.userMemberMap[user.ID]; ok {
|
||||||
if b.userMemberMap[user.ID].Nick != "" {
|
if b.userMemberMap[user.ID] != nil {
|
||||||
// only return if nick is set
|
if b.userMemberMap[user.ID].Nick != "" {
|
||||||
return b.userMemberMap[user.ID].Nick
|
// only return if nick is set
|
||||||
|
return b.userMemberMap[user.ID].Nick
|
||||||
|
}
|
||||||
|
// otherwise return username
|
||||||
|
return user.Username
|
||||||
}
|
}
|
||||||
// otherwise return username
|
|
||||||
return user.Username
|
|
||||||
}
|
}
|
||||||
// if we didn't find nick, search for it
|
// if we didn't find nick, search for it
|
||||||
b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
|
b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
|
||||||
@@ -195,3 +213,28 @@ func (b *bdiscord) replaceRoleMentions(text string) string {
|
|||||||
}
|
}
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bdiscord) replaceChannelMentions(text string) string {
|
||||||
|
var err error
|
||||||
|
re := regexp.MustCompile("<#[0-9]+>")
|
||||||
|
text = re.ReplaceAllStringFunc(text, func(m string) string {
|
||||||
|
channel := b.getChannelName(m[2 : len(m)-1])
|
||||||
|
// if at first don't succeed, try again
|
||||||
|
if channel == "" {
|
||||||
|
b.Channels, err = b.c.GuildChannels(b.guildID)
|
||||||
|
if err != nil {
|
||||||
|
return "#unknownchannel"
|
||||||
|
}
|
||||||
|
channel = b.getChannelName(m[2 : len(m)-1])
|
||||||
|
return channel
|
||||||
|
}
|
||||||
|
return channel
|
||||||
|
})
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bdiscord) stripCustomoji(text string) string {
|
||||||
|
// <:doge:302803592035958784>
|
||||||
|
re := regexp.MustCompile("<(:.*?:)[0-9]+>")
|
||||||
|
return re.ReplaceAllString(text, `$1`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ func New(cfg config.Protocol, account string, c chan config.Message) *Birc {
|
|||||||
if b.Config.MessageQueue == 0 {
|
if b.Config.MessageQueue == 0 {
|
||||||
b.Config.MessageQueue = 30
|
b.Config.MessageQueue = 30
|
||||||
}
|
}
|
||||||
|
if b.Config.MessageLength == 0 {
|
||||||
|
b.Config.MessageLength = 400
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,9 +112,11 @@ func (b *Birc) Send(msg config.Message) error {
|
|||||||
}
|
}
|
||||||
if strings.HasPrefix(msg.Text, "!") {
|
if strings.HasPrefix(msg.Text, "!") {
|
||||||
b.Command(&msg)
|
b.Command(&msg)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
for _, text := range strings.Split(msg.Text, "\n") {
|
for _, text := range strings.Split(msg.Text, "\n") {
|
||||||
|
if len(text) > b.Config.MessageLength {
|
||||||
|
text = text[:b.Config.MessageLength] + " <message clipped>"
|
||||||
|
}
|
||||||
if len(b.Local) < b.Config.MessageQueue {
|
if len(b.Local) < b.Config.MessageQueue {
|
||||||
if len(b.Local) == b.Config.MessageQueue-1 {
|
if len(b.Local) == b.Config.MessageQueue-1 {
|
||||||
text = text + " <message clipped>"
|
text = text + " <message clipped>"
|
||||||
@@ -167,14 +172,19 @@ func (b *Birc) handleNewConnection(event *irc.Event) {
|
|||||||
i.AddCallback("JOIN", b.handleJoinPart)
|
i.AddCallback("JOIN", b.handleJoinPart)
|
||||||
i.AddCallback("PART", b.handleJoinPart)
|
i.AddCallback("PART", b.handleJoinPart)
|
||||||
i.AddCallback("QUIT", b.handleJoinPart)
|
i.AddCallback("QUIT", b.handleJoinPart)
|
||||||
|
i.AddCallback("KICK", b.handleJoinPart)
|
||||||
i.AddCallback("*", b.handleOther)
|
i.AddCallback("*", b.handleOther)
|
||||||
// we are now fully connected
|
// we are now fully connected
|
||||||
b.connected <- struct{}{}
|
b.connected <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Birc) handleJoinPart(event *irc.Event) {
|
func (b *Birc) handleJoinPart(event *irc.Event) {
|
||||||
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
|
|
||||||
channel := event.Arguments[0]
|
channel := event.Arguments[0]
|
||||||
|
if event.Code == "KICK" {
|
||||||
|
flog.Infof("Got kicked from %s by %s", channel, event.Nick)
|
||||||
|
b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
|
||||||
|
return
|
||||||
|
}
|
||||||
if event.Code == "QUIT" {
|
if event.Code == "QUIT" {
|
||||||
if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") {
|
if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") {
|
||||||
flog.Infof("%s reconnecting ..", b.Account)
|
flog.Infof("%s reconnecting ..", b.Account)
|
||||||
@@ -182,6 +192,7 @@ func (b *Birc) handleJoinPart(event *irc.Event) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
|
||||||
b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
|
b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
|
||||||
flog.Debugf("handle %#v", event)
|
flog.Debugf("handle %#v", event)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package bmatrix
|
package bmatrix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
matrix "github.com/matrix-org/gomatrix"
|
matrix "github.com/matrix-org/gomatrix"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bmatrix struct {
|
type Bmatrix struct {
|
||||||
@@ -101,8 +103,13 @@ func (b *Bmatrix) handlematrix() error {
|
|||||||
flog.Debugf("Unknown room %s", ev.RoomID)
|
flog.Debugf("Unknown room %s", ev.RoomID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
username := ev.Sender[1:]
|
||||||
|
if b.Config.NoHomeServerSuffix {
|
||||||
|
re := regexp.MustCompile("(.*?):.*")
|
||||||
|
username = re.ReplaceAllString(username, `$1`)
|
||||||
|
}
|
||||||
flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
|
flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
|
||||||
b.Remote <- config.Message{Username: ev.Sender, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account}
|
b.Remote <- config.Message{Username: username, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account}
|
||||||
}
|
}
|
||||||
flog.Debugf("Received: %#v", ev)
|
flog.Debugf("Received: %#v", ev)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ func (b *Bmattermost) Connect() error {
|
|||||||
flog.Info("Connection succeeded")
|
flog.Info("Connection succeeded")
|
||||||
b.TeamId = b.mc.GetTeamId()
|
b.TeamId = b.mc.GetTeamId()
|
||||||
go b.mc.WsReceiver()
|
go b.mc.WsReceiver()
|
||||||
|
go b.mc.StatusLoop()
|
||||||
}
|
}
|
||||||
go b.handleMatter()
|
go b.handleMatter()
|
||||||
return nil
|
return nil
|
||||||
@@ -100,6 +101,7 @@ func (b *Bmattermost) Send(msg config.Message) error {
|
|||||||
}
|
}
|
||||||
if !b.Config.UseAPI {
|
if !b.Config.UseAPI {
|
||||||
matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
|
matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
|
||||||
|
matterMessage.IconURL = msg.Avatar
|
||||||
matterMessage.Channel = channel
|
matterMessage.Channel = channel
|
||||||
matterMessage.UserName = nick
|
matterMessage.UserName = nick
|
||||||
matterMessage.Type = ""
|
matterMessage.Type = ""
|
||||||
@@ -131,14 +133,26 @@ func (b *Bmattermost) handleMatter() {
|
|||||||
|
|
||||||
func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
||||||
for message := range b.mc.MessageChan {
|
for message := range b.mc.MessageChan {
|
||||||
|
flog.Debugf("%#v", message.Raw.Data)
|
||||||
|
if message.Type == "system_join_leave" ||
|
||||||
|
message.Type == "system_join_channel" ||
|
||||||
|
message.Type == "system_leave_channel" {
|
||||||
|
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
|
||||||
|
b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
|
||||||
|
continue
|
||||||
|
}
|
||||||
// do not post our own messages back to irc
|
// do not post our own messages back to irc
|
||||||
// only listen to message from our team
|
// only listen to message from our team
|
||||||
if message.Raw.Event == "posted" && b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
|
if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited") &&
|
||||||
|
b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
|
||||||
flog.Debugf("Receiving from matterclient %#v", message)
|
flog.Debugf("Receiving from matterclient %#v", message)
|
||||||
m := &MMMessage{}
|
m := &MMMessage{}
|
||||||
m.Username = message.Username
|
m.Username = message.Username
|
||||||
m.Channel = message.Channel
|
m.Channel = message.Channel
|
||||||
m.Text = message.Text
|
m.Text = message.Text
|
||||||
|
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
|
||||||
|
m.Text = message.Text + b.Config.EditSuffix
|
||||||
|
}
|
||||||
if len(message.Post.FileIds) > 0 {
|
if len(message.Post.FileIds) > 0 {
|
||||||
for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
|
for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
|
||||||
m.Text = m.Text + "\n" + link
|
m.Text = m.Text + "\n" + link
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ func (b *Bslack) JoinChannel(channel string) error {
|
|||||||
}
|
}
|
||||||
_, err := b.sc.JoinChannel(channel)
|
_, err := b.sc.JoinChannel(channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
if err.Error() != "name_taken" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -87,9 +89,6 @@ func (b *Bslack) JoinChannel(channel string) error {
|
|||||||
|
|
||||||
func (b *Bslack) Send(msg config.Message) error {
|
func (b *Bslack) Send(msg config.Message) error {
|
||||||
flog.Debugf("Receiving %#v", msg)
|
flog.Debugf("Receiving %#v", msg)
|
||||||
if msg.Account == b.Account {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
nick := msg.Username
|
nick := msg.Username
|
||||||
message := msg.Text
|
message := msg.Text
|
||||||
channel := msg.Channel
|
channel := msg.Channel
|
||||||
@@ -199,6 +198,11 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
|||||||
// ignore first message
|
// ignore first message
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
flog.Debugf("Receiving from slackclient %#v", ev)
|
flog.Debugf("Receiving from slackclient %#v", ev)
|
||||||
|
if !b.Config.EditDisable && ev.SubMessage != nil {
|
||||||
|
flog.Debugf("SubMessage %#v", ev.SubMessage)
|
||||||
|
ev.User = ev.SubMessage.User
|
||||||
|
ev.Text = ev.SubMessage.Text + b.Config.EditSuffix
|
||||||
|
}
|
||||||
// use our own func because rtm.GetChannelInfo doesn't work for private channels
|
// use our own func because rtm.GetChannelInfo doesn't work for private channels
|
||||||
channel, err := b.getChannelByID(ev.Channel)
|
channel, err := b.getChannelByID(ev.Channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -76,29 +76,36 @@ func (b *Btelegram) Send(msg config.Message) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
||||||
username := ""
|
|
||||||
text := ""
|
|
||||||
channel := ""
|
|
||||||
for update := range updates {
|
for update := range updates {
|
||||||
var message *tgbotapi.Message
|
var message *tgbotapi.Message
|
||||||
|
username := ""
|
||||||
|
channel := ""
|
||||||
|
text := ""
|
||||||
// handle channels
|
// handle channels
|
||||||
if update.ChannelPost != nil {
|
if update.ChannelPost != nil {
|
||||||
message = update.ChannelPost
|
message = update.ChannelPost
|
||||||
}
|
}
|
||||||
if update.EditedChannelPost != nil {
|
if update.EditedChannelPost != nil && !b.Config.EditDisable {
|
||||||
message = update.EditedChannelPost
|
message = update.EditedChannelPost
|
||||||
|
message.Text = message.Text + b.Config.EditSuffix
|
||||||
}
|
}
|
||||||
// handle groups
|
// handle groups
|
||||||
if update.Message != nil {
|
if update.Message != nil {
|
||||||
message = update.Message
|
message = update.Message
|
||||||
}
|
}
|
||||||
if update.EditedMessage != nil {
|
if update.EditedMessage != nil && !b.Config.EditDisable {
|
||||||
message = update.EditedMessage
|
message = update.EditedMessage
|
||||||
|
message.Text = message.Text + b.Config.EditSuffix
|
||||||
}
|
}
|
||||||
if message.From != nil {
|
if message.From != nil {
|
||||||
username = message.From.FirstName
|
if b.Config.UseFirstName {
|
||||||
|
username = message.From.FirstName
|
||||||
|
}
|
||||||
if username == "" {
|
if username == "" {
|
||||||
username = message.From.UserName
|
username = message.From.UserName
|
||||||
|
if username == "" {
|
||||||
|
username = message.From.FirstName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
text = message.Text
|
text = message.Text
|
||||||
channel = strconv.FormatInt(message.Chat.ID, 10)
|
channel = strconv.FormatInt(message.Chat.ID, 10)
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func (b *Bxmpp) handleXmpp() error {
|
|||||||
var channel, nick string
|
var channel, nick string
|
||||||
if v.Type == "groupchat" {
|
if v.Type == "groupchat" {
|
||||||
s := strings.Split(v.Remote, "@")
|
s := strings.Split(v.Remote, "@")
|
||||||
if len(s) == 2 {
|
if len(s) >= 2 {
|
||||||
channel = s[0]
|
channel = s[0]
|
||||||
}
|
}
|
||||||
s = strings.Split(s[1], "/")
|
s = strings.Split(s[1], "/")
|
||||||
|
|||||||
55
changelog.md
55
changelog.md
@@ -1,8 +1,59 @@
|
|||||||
# v0.11.0-dev
|
# v0.13.0
|
||||||
## New features
|
## New features
|
||||||
* general: reusing the same account on multiple gateways now also reuses the connection.
|
* irc: Limit message length. ```MessageLength=400```
|
||||||
|
Maximum length of message sent to irc server. If it exceeds <message clipped> will be add to the message.
|
||||||
|
* irc: Add NOPINGNICK option.
|
||||||
|
The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged.
|
||||||
|
See https://github.com/42wim/matterbridge/issues/175 for more information
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* slack: Fix sending to different channels on same account (slack). Closes #177
|
||||||
|
* telegram: Fix incorrect usernames being sent. Closes #181
|
||||||
|
|
||||||
|
|
||||||
|
# v0.12.1
|
||||||
|
## New features
|
||||||
|
* telegram: Add UseFirstName option (telegram). Closes #144
|
||||||
|
* matrix: Add NoHomeServerSuffix. Option to disable homeserver on username (matrix). Closes #160.
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* xmpp: Add Compatibility for Cisco Jabber (xmpp) (#166)
|
||||||
|
* irc: Fix JoinChannel argument to use IRC channel key (#172)
|
||||||
|
* discord: Fix possible crash on nil (discord)
|
||||||
|
* discord: Replace long ids in channel metions (discord). Fixes #174
|
||||||
|
|
||||||
|
# v0.12.0
|
||||||
|
## Changes
|
||||||
|
* general: edited messages are now being sent by default on discord/mattermost/telegram/slack. See "New Features"
|
||||||
|
|
||||||
|
## New features
|
||||||
|
* general: add support for edited messages.
|
||||||
|
Add new keyword EditDisable (false/true), default false. Which means by default edited messages will be sent to other bridges.
|
||||||
|
Add new keyword EditSuffix , default "". You can change this eg to "(edited)", this will be appended to every edit message.
|
||||||
|
* mattermost: support mattermost v3.9.x
|
||||||
|
* general: Add support for HTTP{S}_PROXY env variables (#162)
|
||||||
|
* discord: Strip custom emoji metadata (discord). Closes #148
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* slack: Ignore error on private channel join (slack) Fixes #150
|
||||||
|
* mattermost: fix crash on reconnects when server is down. Closes #163
|
||||||
|
* irc: Relay messages starting with ! (irc). Closes #164
|
||||||
|
|
||||||
|
# v0.11.0
|
||||||
|
## New features
|
||||||
|
* general: reusing the same account on multiple gateways now also reuses the connection.
|
||||||
This is particuarly useful for irc. See #87
|
This is particuarly useful for irc. See #87
|
||||||
* general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration
|
* general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration
|
||||||
|
* telegram: Support edited messages (telegram). See #141
|
||||||
|
* mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147
|
||||||
|
* mattermost: Reconnect on session removal/timeout (mattermost)
|
||||||
|
* mattermost: Support mattermost v3.8.x
|
||||||
|
* irc: Rejoin channel when kicked (irc).
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* mattermost: Remove space after nick (mattermost). Closes #142
|
||||||
|
* mattermost: Modify iconurl correctly (mattermost).
|
||||||
|
* irc: Fix join/leave regression (irc)
|
||||||
|
|
||||||
# v0.10.3
|
# v0.10.3
|
||||||
## Bugfix
|
## Bugfix
|
||||||
|
|||||||
@@ -103,6 +103,15 @@ func (gw *Gateway) handleReceive() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if msg.Event == config.EVENT_REJOIN_CHANNELS {
|
||||||
|
for _, br := range gw.Bridges {
|
||||||
|
if msg.Account == br.Account {
|
||||||
|
br.Joined = make(map[string]bool)
|
||||||
|
br.JoinChannels()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !gw.ignoreMessage(&msg) {
|
if !gw.ignoreMessage(&msg) {
|
||||||
msg.Timestamp = time.Now()
|
msg.Timestamp = time.Now()
|
||||||
for _, br := range gw.Bridges {
|
for _, br := range gw.Bridges {
|
||||||
@@ -183,13 +192,15 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
originchannel := msg.Channel
|
originchannel := msg.Channel
|
||||||
|
origmsg := msg
|
||||||
for _, channel := range gw.DestChannelFunc(&msg, *dest) {
|
for _, channel := range gw.DestChannelFunc(&msg, *dest) {
|
||||||
// do not send to ourself
|
// do not send to ourself
|
||||||
if channel.ID == getChannelID(msg) {
|
if channel.ID == getChannelID(origmsg) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
|
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
|
||||||
msg.Channel = channel.Name
|
msg.Channel = channel.Name
|
||||||
|
gw.modifyAvatar(&msg, dest)
|
||||||
gw.modifyUsername(&msg, dest)
|
gw.modifyUsername(&msg, dest)
|
||||||
// for api we need originchannel as channel
|
// for api we need originchannel as channel
|
||||||
if dest.Protocol == "api" {
|
if dest.Protocol == "api" {
|
||||||
@@ -223,12 +234,24 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
|
|||||||
if nick == "" {
|
if nick == "" {
|
||||||
nick = dest.Config.RemoteNickFormat
|
nick = dest.Config.RemoteNickFormat
|
||||||
}
|
}
|
||||||
|
nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:1]+""+msg.Username[1:], -1)
|
||||||
nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
|
nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
|
||||||
nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
|
nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
|
||||||
nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
|
nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
|
||||||
msg.Username = nick
|
msg.Username = nick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) {
|
||||||
|
iconurl := gw.Config.General.IconURL
|
||||||
|
if iconurl == "" {
|
||||||
|
iconurl = dest.Config.IconURL
|
||||||
|
}
|
||||||
|
iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
|
||||||
|
if msg.Avatar == "" {
|
||||||
|
msg.Avatar = iconurl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getChannelID(msg config.Message) string {
|
func getChannelID(msg config.Message) string {
|
||||||
return msg.Channel + msg.Account
|
return msg.Channel + msg.Account
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "0.11.0-dev"
|
version = "0.13.0"
|
||||||
githash string
|
githash string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,15 @@ MessageDelay=1300
|
|||||||
|
|
||||||
#Maximum amount of messages to hold in queue. If queue is full
|
#Maximum amount of messages to hold in queue. If queue is full
|
||||||
#messages will be dropped.
|
#messages will be dropped.
|
||||||
#<clipped> will be add to the message that fills the queue.
|
#<message clipped> will be add to the message that fills the queue.
|
||||||
#OPTIONAL (default 30)
|
#OPTIONAL (default 30)
|
||||||
MessageQueue=30
|
MessageQueue=30
|
||||||
|
|
||||||
|
#Maximum length of message sent to irc server. If it exceeds
|
||||||
|
#<message clipped> will be add to the message.
|
||||||
|
#OPTIONAL (default 400)
|
||||||
|
MessageLength=400
|
||||||
|
|
||||||
#Nicks you want to ignore.
|
#Nicks you want to ignore.
|
||||||
#Messages from those users will not be sent to other bridges.
|
#Messages from those users will not be sent to other bridges.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
@@ -61,10 +66,12 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
|
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
|
||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
|
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
|
||||||
#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
|
#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
|
||||||
|
#The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged. See https://github.com/42wim/matterbridge/issues/175 for more information
|
||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -114,7 +121,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -157,7 +165,8 @@ IgnoreNicks="spammer1 spammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -197,9 +206,9 @@ IconURL="http://youricon.png"
|
|||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
useAPI=false
|
useAPI=false
|
||||||
|
|
||||||
#The mattermost hostname.
|
#The mattermost hostname. (do not prefix it with http or https)
|
||||||
#REQUIRED (when useAPI=true)
|
#REQUIRED (when useAPI=true)
|
||||||
Server="yourmattermostserver.domain"
|
Server="yourmattermostserver.domain"
|
||||||
|
|
||||||
#Your team on mattermost.
|
#Your team on mattermost.
|
||||||
#REQUIRED (when useAPI=true)
|
#REQUIRED (when useAPI=true)
|
||||||
@@ -238,6 +247,14 @@ NicksPerRow=4
|
|||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
PrefixMessagesWithNick=false
|
PrefixMessagesWithNick=false
|
||||||
|
|
||||||
|
#Disable sending of edits to other bridges
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
EditDisable=false
|
||||||
|
|
||||||
|
#Message to be appended to every edited message
|
||||||
|
#OPTIONAL (default empty)
|
||||||
|
EditSuffix=" (edited)"
|
||||||
|
|
||||||
#Nicks you want to ignore.
|
#Nicks you want to ignore.
|
||||||
#Messages from those users will not be sent to other bridges.
|
#Messages from those users will not be sent to other bridges.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
@@ -250,7 +267,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -282,7 +300,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -342,6 +361,14 @@ NickFormatter="plain"
|
|||||||
#OPTIONAL (default 4)
|
#OPTIONAL (default 4)
|
||||||
NicksPerRow=4
|
NicksPerRow=4
|
||||||
|
|
||||||
|
#Disable sending of edits to other bridges
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
EditDisable=true
|
||||||
|
|
||||||
|
#Message to be appended to every edited message
|
||||||
|
#OPTIONAL (default empty)
|
||||||
|
EditSuffix=" (edited)"
|
||||||
|
|
||||||
#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat
|
#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat
|
||||||
#Useful if username overrides for incoming webhooks isn't enabled on the
|
#Useful if username overrides for incoming webhooks isn't enabled on the
|
||||||
#slack server. If you set PrefixMessagesWithNick to true, each message
|
#slack server. If you set PrefixMessagesWithNick to true, each message
|
||||||
@@ -362,7 +389,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -385,6 +413,14 @@ Token="Yourtokenhere"
|
|||||||
#REQUIRED
|
#REQUIRED
|
||||||
Server="yourservername"
|
Server="yourservername"
|
||||||
|
|
||||||
|
#Disable sending of edits to other bridges
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
EditDisable=false
|
||||||
|
|
||||||
|
#Message to be appended to every edited message
|
||||||
|
#OPTIONAL (default empty)
|
||||||
|
EditSuffix=" (edited)"
|
||||||
|
|
||||||
#Nicks you want to ignore.
|
#Nicks you want to ignore.
|
||||||
#Messages from those users will not be sent to other bridges.
|
#Messages from those users will not be sent to other bridges.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
@@ -397,7 +433,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -420,6 +457,20 @@ Token="Yourtokenhere"
|
|||||||
#See https://core.telegram.org/bots/api#html-style
|
#See https://core.telegram.org/bots/api#html-style
|
||||||
MessageFormat=""
|
MessageFormat=""
|
||||||
|
|
||||||
|
#If enabled use the "First Name" as username. If this is empty use the Username
|
||||||
|
#If disabled use the "Username" as username. If this is empty use the First Name
|
||||||
|
#If all names are empty, username will be "unknown"
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
UseFirstName=false
|
||||||
|
|
||||||
|
#Disable sending of edits to other bridges
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
EditDisable=false
|
||||||
|
|
||||||
|
#Message to be appended to every edited message
|
||||||
|
#OPTIONAL (default empty)
|
||||||
|
EditSuffix=" (edited)"
|
||||||
|
|
||||||
#Nicks you want to ignore.
|
#Nicks you want to ignore.
|
||||||
#Messages from those users will not be sent to other bridges.
|
#Messages from those users will not be sent to other bridges.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
@@ -432,7 +483,8 @@ IgnoreNicks="spammer1 spammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -489,7 +541,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -513,6 +566,11 @@ Server="https://matrix.org"
|
|||||||
Login="yourlogin"
|
Login="yourlogin"
|
||||||
Password="yourpass"
|
Password="yourpass"
|
||||||
|
|
||||||
|
#Whether to send the homeserver suffix. eg ":matrix.org" in @username:matrix.org
|
||||||
|
#to other bridges, or only send "username".(true only sends username)
|
||||||
|
#OPTIONAL (default false)
|
||||||
|
NoHomeServerSuffix=false
|
||||||
|
|
||||||
#Whether to prefix messages from other bridges to matrix with the sender's nick.
|
#Whether to prefix messages from other bridges to matrix with the sender's nick.
|
||||||
#Useful if username overrides for incoming webhooks isn't enabled on the
|
#Useful if username overrides for incoming webhooks isn't enabled on the
|
||||||
#matrix server. If you set PrefixMessagesWithNick to true, each message
|
#matrix server. If you set PrefixMessagesWithNick to true, each message
|
||||||
@@ -532,7 +590,8 @@ IgnoreNicks="spammer1 spammer2"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||||
|
|
||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
|
#Enable to show users joins/parts from other bridges
|
||||||
|
#Only works hiding/show messages from irc and mattermost bridge for now
|
||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
ShowJoinPart=false
|
ShowJoinPart=false
|
||||||
|
|
||||||
@@ -615,7 +674,8 @@ enable=true
|
|||||||
# see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau)
|
# see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau)
|
||||||
#hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel)
|
#hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel)
|
||||||
#rocketchat - #channel (# is required)
|
#rocketchat - #channel (# is required)
|
||||||
#matrix - #channel:server (eg #yourchannel:matrix.org)
|
#matrix - #channel:server (eg #yourchannel:matrix.org)
|
||||||
|
# - encrypted rooms are not supported in matrix
|
||||||
#REQUIRED
|
#REQUIRED
|
||||||
channel="#testing"
|
channel="#testing"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
[mattermost]
|
[mattermost]
|
||||||
[mattermost.work]
|
[mattermost.work]
|
||||||
useAPI=true
|
useAPI=true
|
||||||
Server="yourmattermostserver.domain"
|
#do not prefix it wit http:// or https://
|
||||||
|
Server="yourmattermostserver.domain"
|
||||||
Team="yourteam"
|
Team="yourteam"
|
||||||
Login="yourlogin"
|
Login="yourlogin"
|
||||||
Password="yourpass"
|
Password="yourpass"
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/cookiejar"
|
"net/http/cookiejar"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -34,6 +36,7 @@ type Message struct {
|
|||||||
Channel string
|
Channel string
|
||||||
Username string
|
Username string
|
||||||
Text string
|
Text string
|
||||||
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Team struct {
|
type Team struct {
|
||||||
@@ -47,19 +50,20 @@ type Team struct {
|
|||||||
type MMClient struct {
|
type MMClient struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
*Credentials
|
*Credentials
|
||||||
Team *Team
|
Team *Team
|
||||||
OtherTeams []*Team
|
OtherTeams []*Team
|
||||||
Client *model.Client
|
Client *model.Client
|
||||||
User *model.User
|
User *model.User
|
||||||
Users map[string]*model.User
|
Users map[string]*model.User
|
||||||
MessageChan chan *Message
|
MessageChan chan *Message
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
WsClient *websocket.Conn
|
WsClient *websocket.Conn
|
||||||
WsQuit bool
|
WsQuit bool
|
||||||
WsAway bool
|
WsAway bool
|
||||||
WsConnected bool
|
WsConnected bool
|
||||||
WsSequence int64
|
WsSequence int64
|
||||||
WsPingChan chan *model.WebSocketResponse
|
WsPingChan chan *model.WebSocketResponse
|
||||||
|
ServerVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(login, pass, team, server string) *MMClient {
|
func New(login, pass, team, server string) *MMClient {
|
||||||
@@ -102,8 +106,27 @@ func (m *MMClient) Login() error {
|
|||||||
}
|
}
|
||||||
// login to mattermost
|
// login to mattermost
|
||||||
m.Client = model.NewClient(uriScheme + m.Credentials.Server)
|
m.Client = model.NewClient(uriScheme + m.Credentials.Server)
|
||||||
m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
|
m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, Proxy: http.ProxyFromEnvironment}
|
||||||
m.Client.HttpClient.Timeout = time.Second * 10
|
m.Client.HttpClient.Timeout = time.Second * 10
|
||||||
|
|
||||||
|
for {
|
||||||
|
d := b.Duration()
|
||||||
|
// bogus call to get the serverversion
|
||||||
|
m.Client.GetClientProperties()
|
||||||
|
if firstConnection && !supportedVersion(m.Client.ServerVersion) {
|
||||||
|
return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion)
|
||||||
|
}
|
||||||
|
m.ServerVersion = m.Client.ServerVersion
|
||||||
|
if m.ServerVersion == "" {
|
||||||
|
m.log.Debugf("Server not up yet, reconnecting in %s", d)
|
||||||
|
time.Sleep(d)
|
||||||
|
} else {
|
||||||
|
m.log.Infof("Found version %s", m.ServerVersion)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.Reset()
|
||||||
|
|
||||||
var myinfo *model.Result
|
var myinfo *model.Result
|
||||||
var appErr *model.AppError
|
var appErr *model.AppError
|
||||||
var logmsg = "trying login"
|
var logmsg = "trying login"
|
||||||
@@ -177,6 +200,7 @@ func (m *MMClient) Login() error {
|
|||||||
}
|
}
|
||||||
b.Reset()
|
b.Reset()
|
||||||
|
|
||||||
|
m.log.Debug("WsClient: connected")
|
||||||
m.WsSequence = 1
|
m.WsSequence = 1
|
||||||
m.WsPingChan = make(chan *model.WebSocketResponse)
|
m.WsPingChan = make(chan *model.WebSocketResponse)
|
||||||
// only start to parse WS messages when login is completely done
|
// only start to parse WS messages when login is completely done
|
||||||
@@ -238,7 +262,7 @@ func (m *MMClient) WsReceiver() {
|
|||||||
|
|
||||||
func (m *MMClient) parseMessage(rmsg *Message) {
|
func (m *MMClient) parseMessage(rmsg *Message) {
|
||||||
switch rmsg.Raw.Event {
|
switch rmsg.Raw.Event {
|
||||||
case model.WEBSOCKET_EVENT_POSTED:
|
case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED:
|
||||||
m.parseActionPost(rmsg)
|
m.parseActionPost(rmsg)
|
||||||
/*
|
/*
|
||||||
case model.ACTION_USER_REMOVED:
|
case model.ACTION_USER_REMOVED:
|
||||||
@@ -266,7 +290,18 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
|
|||||||
}
|
}
|
||||||
rmsg.Username = m.GetUser(data.UserId).Username
|
rmsg.Username = m.GetUser(data.UserId).Username
|
||||||
rmsg.Channel = m.GetChannelName(data.ChannelId)
|
rmsg.Channel = m.GetChannelName(data.ChannelId)
|
||||||
rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string))
|
rmsg.Type = data.Type
|
||||||
|
teamid, _ := rmsg.Raw.Data["team_id"].(string)
|
||||||
|
// edit messsages have no team_id for some reason
|
||||||
|
if teamid == "" {
|
||||||
|
// we can find the team_id from the channelid
|
||||||
|
result, _ := m.Client.GetChannel(data.ChannelId, "")
|
||||||
|
teamid = result.Data.(*model.ChannelData).Channel.TeamId
|
||||||
|
rmsg.Raw.Data["team_id"] = teamid
|
||||||
|
}
|
||||||
|
if teamid != "" {
|
||||||
|
rmsg.Team = m.GetTeamName(teamid)
|
||||||
|
}
|
||||||
// direct message
|
// direct message
|
||||||
if rmsg.Raw.Data["channel_type"] == "D" {
|
if rmsg.Raw.Data["channel_type"] == "D" {
|
||||||
rmsg.Channel = m.GetUser(data.UserId).Username
|
rmsg.Channel = m.GetUser(data.UserId).Username
|
||||||
@@ -292,7 +327,12 @@ func (m *MMClient) UpdateChannels() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(err.DetailedError)
|
return errors.New(err.DetailedError)
|
||||||
}
|
}
|
||||||
mmchannels2, err := m.Client.GetMoreChannels("")
|
var mmchannels2 *model.Result
|
||||||
|
if m.mmVersion() >= 3.8 {
|
||||||
|
mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000)
|
||||||
|
} else {
|
||||||
|
mmchannels2, err = m.Client.GetMoreChannels("")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(err.DetailedError)
|
return errors.New(err.DetailedError)
|
||||||
}
|
}
|
||||||
@@ -427,6 +467,14 @@ func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
|
|||||||
|
|
||||||
func (m *MMClient) UpdateLastViewed(channelId string) {
|
func (m *MMClient) UpdateLastViewed(channelId string) {
|
||||||
m.log.Debugf("posting lastview %#v", channelId)
|
m.log.Debugf("posting lastview %#v", channelId)
|
||||||
|
if m.mmVersion() >= 3.8 {
|
||||||
|
view := model.ChannelView{ChannelId: channelId}
|
||||||
|
res, _ := m.Client.ViewChannel(view)
|
||||||
|
if res == false {
|
||||||
|
m.log.Errorf("ChannelView update for %s failed", channelId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
_, err := m.Client.UpdateLastViewedAt(channelId, true)
|
_, err := m.Client.UpdateLastViewedAt(channelId, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.log.Error(err)
|
m.log.Error(err)
|
||||||
@@ -628,6 +676,7 @@ func (m *MMClient) StatusLoop() {
|
|||||||
m.Logout()
|
m.Logout()
|
||||||
m.WsQuit = false
|
m.WsQuit = false
|
||||||
m.Login()
|
m.Login()
|
||||||
|
go m.WsReceiver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 60)
|
time.Sleep(time.Second * 60)
|
||||||
@@ -659,7 +708,11 @@ func (m *MMClient) initUser() error {
|
|||||||
return errors.New(err.DetailedError)
|
return errors.New(err.DetailedError)
|
||||||
}
|
}
|
||||||
t.Channels = mmchannels.Data.(*model.ChannelList)
|
t.Channels = mmchannels.Data.(*model.ChannelList)
|
||||||
mmchannels, err = m.Client.GetMoreChannels("")
|
if m.mmVersion() >= 3.8 {
|
||||||
|
mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000)
|
||||||
|
} else {
|
||||||
|
mmchannels, err = m.Client.GetMoreChannels("")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(err.DetailedError)
|
return errors.New(err.DetailedError)
|
||||||
}
|
}
|
||||||
@@ -687,3 +740,19 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err
|
|||||||
m.WsClient.WriteJSON(req)
|
m.WsClient.WriteJSON(req)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) mmVersion() float64 {
|
||||||
|
v, _ := strconv.ParseFloat(m.ServerVersion[0:3], 64)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func supportedVersion(version string) bool {
|
||||||
|
if strings.HasPrefix(version, "3.5.0") ||
|
||||||
|
strings.HasPrefix(version, "3.6.0") ||
|
||||||
|
strings.HasPrefix(version, "3.7.0") ||
|
||||||
|
strings.HasPrefix(version, "3.8.0") ||
|
||||||
|
strings.HasPrefix(version, "3.9.0") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
import l4g "code.google.com/p/log4go"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log := l4g.NewLogger()
|
|
||||||
defer log.Close()
|
|
||||||
log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
|
|
||||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
import l4g "code.google.com/p/log4go"
|
|
||||||
|
|
||||||
const (
|
|
||||||
filename = "flw.log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Get a new logger instance
|
|
||||||
log := l4g.NewLogger()
|
|
||||||
|
|
||||||
// Create a default logger that is logging messages of FINE or higher
|
|
||||||
log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false))
|
|
||||||
log.Close()
|
|
||||||
|
|
||||||
/* Can also specify manually via the following: (these are the defaults) */
|
|
||||||
flw := l4g.NewFileLogWriter(filename, false)
|
|
||||||
flw.SetFormat("[%D %T] [%L] (%S) %M")
|
|
||||||
flw.SetRotate(false)
|
|
||||||
flw.SetRotateSize(0)
|
|
||||||
flw.SetRotateLines(0)
|
|
||||||
flw.SetRotateDaily(false)
|
|
||||||
log.AddFilter("file", l4g.FINE, flw)
|
|
||||||
|
|
||||||
// Log some experimental messages
|
|
||||||
log.Finest("Everything is created now (notice that I will not be printing to the file)")
|
|
||||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
|
||||||
log.Critical("Time to close out!")
|
|
||||||
|
|
||||||
// Close the log
|
|
||||||
log.Close()
|
|
||||||
|
|
||||||
// Print what was logged to the file (yes, I know I'm skipping error checking)
|
|
||||||
fd, _ := os.Open(filename)
|
|
||||||
in := bufio.NewReader(fd)
|
|
||||||
fmt.Print("Messages logged to file were: (line numbers not included)\n")
|
|
||||||
for lineno := 1; ; lineno++ {
|
|
||||||
line, err := in.ReadString('\n')
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fmt.Printf("%3d:\t%s", lineno, line)
|
|
||||||
}
|
|
||||||
fd.Close()
|
|
||||||
|
|
||||||
// Remove the file so it's not lying around
|
|
||||||
os.Remove(filename)
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
port = flag.String("p", "12124", "Port number to listen on")
|
|
||||||
)
|
|
||||||
|
|
||||||
func e(err error) {
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Erroring out: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
// Bind to the port
|
|
||||||
bind, err := net.ResolveUDPAddr("0.0.0.0:" + *port)
|
|
||||||
e(err)
|
|
||||||
|
|
||||||
// Create listener
|
|
||||||
listener, err := net.ListenUDP("udp", bind)
|
|
||||||
e(err)
|
|
||||||
|
|
||||||
fmt.Printf("Listening to port %s...\n", *port)
|
|
||||||
for {
|
|
||||||
// read into a new buffer
|
|
||||||
buffer := make([]byte, 1024)
|
|
||||||
_, _, err := listener.ReadFrom(buffer)
|
|
||||||
e(err)
|
|
||||||
|
|
||||||
// log to standard output
|
|
||||||
fmt.Println(string(buffer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
import l4g "code.google.com/p/log4go"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log := l4g.NewLogger()
|
|
||||||
log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
|
|
||||||
|
|
||||||
// Run `nc -u -l -p 12124` or similar before you run this to see the following message
|
|
||||||
log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
|
|
||||||
|
|
||||||
// This makes sure the output stream buffer is written
|
|
||||||
log.Close()
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import l4g "code.google.com/p/log4go"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Load the configuration (isn't this easy?)
|
|
||||||
l4g.LoadConfiguration("example.xml")
|
|
||||||
|
|
||||||
// And now we're ready!
|
|
||||||
l4g.Finest("This will only go to those of you really cool UDP kids! If you change enabled=true.")
|
|
||||||
l4g.Debug("Oh no! %d + %d = %d!", 2, 2, 2+2)
|
|
||||||
l4g.Info("About that time, eh chaps?")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user