2016-08-14 19:48:51 +00:00
|
|
|
package bxmpp
|
|
|
|
|
|
|
|
import (
|
2021-01-21 21:50:04 +00:00
|
|
|
"bytes"
|
2017-02-14 20:12:02 +00:00
|
|
|
"crypto/tls"
|
2021-01-21 21:50:04 +00:00
|
|
|
"encoding/json"
|
2019-06-30 16:34:38 +00:00
|
|
|
"fmt"
|
2021-01-21 21:50:04 +00:00
|
|
|
"net/http"
|
2021-02-17 20:30:06 +00:00
|
|
|
"net/url"
|
2018-06-09 10:47:40 +00:00
|
|
|
"strings"
|
2019-06-30 16:34:38 +00:00
|
|
|
"sync"
|
2018-06-09 10:47:40 +00:00
|
|
|
"time"
|
|
|
|
|
2018-02-26 23:33:21 +00:00
|
|
|
"github.com/42wim/matterbridge/bridge"
|
2016-08-14 19:48:51 +00:00
|
|
|
"github.com/42wim/matterbridge/bridge/config"
|
2018-02-03 00:11:11 +00:00
|
|
|
"github.com/42wim/matterbridge/bridge/helper"
|
2017-07-20 21:16:43 +00:00
|
|
|
"github.com/jpillora/backoff"
|
2018-02-27 21:55:55 +00:00
|
|
|
"github.com/matterbridge/go-xmpp"
|
2018-06-09 10:47:40 +00:00
|
|
|
"github.com/rs/xid"
|
2016-08-14 19:48:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Bxmpp struct {
|
2018-03-04 22:52:14 +00:00
|
|
|
*bridge.Config
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2019-02-23 22:03:21 +00:00
|
|
|
startTime time.Time
|
2019-05-30 10:31:54 +00:00
|
|
|
xc *xmpp.Client
|
|
|
|
xmppMap map[string]string
|
2019-06-30 16:34:38 +00:00
|
|
|
connected bool
|
|
|
|
sync.RWMutex
|
2020-04-16 20:16:25 +00:00
|
|
|
|
2020-05-24 12:07:36 +00:00
|
|
|
avatarAvailability map[string]bool
|
|
|
|
avatarMap map[string]string
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
|
2018-03-04 22:52:14 +00:00
|
|
|
func New(cfg *bridge.Config) bridge.Bridger {
|
2019-05-30 10:31:54 +00:00
|
|
|
return &Bxmpp{
|
2020-05-24 12:07:36 +00:00
|
|
|
Config: cfg,
|
|
|
|
xmppMap: make(map[string]string),
|
|
|
|
avatarAvailability: make(map[string]bool),
|
|
|
|
avatarMap: make(map[string]string),
|
2019-05-30 10:31:54 +00:00
|
|
|
}
|
2016-08-15 21:16:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bxmpp) Connect() error {
|
2018-03-04 22:52:14 +00:00
|
|
|
b.Log.Infof("Connecting %s", b.GetString("Server"))
|
2019-05-30 10:31:54 +00:00
|
|
|
if err := b.createXMPP(); err != nil {
|
2018-02-26 23:33:21 +00:00
|
|
|
b.Log.Debugf("%#v", err)
|
2016-08-15 21:16:07 +00:00
|
|
|
return err
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2018-02-26 23:33:21 +00:00
|
|
|
b.Log.Info("Connection succeeded")
|
2019-05-30 10:31:54 +00:00
|
|
|
go b.manageConnection()
|
2016-08-15 21:16:07 +00:00
|
|
|
return nil
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 20:12:02 +00:00
|
|
|
func (b *Bxmpp) Disconnect() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-12 12:51:41 +00:00
|
|
|
func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error {
|
2018-06-18 20:55:45 +00:00
|
|
|
if channel.Options.Key != "" {
|
|
|
|
b.Log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
|
|
|
|
b.xc.JoinProtectedMUC(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"), channel.Options.Key, xmpp.NoHistory, 0, nil)
|
|
|
|
} else {
|
|
|
|
b.xc.JoinMUCNoHistory(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"))
|
|
|
|
}
|
2016-09-18 17:21:15 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-27 20:59:37 +00:00
|
|
|
func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
2019-06-30 16:34:38 +00:00
|
|
|
// should be fixed by using a cache instead of dropping
|
|
|
|
if !b.Connected() {
|
|
|
|
return "", fmt.Errorf("bridge %s not connected, dropping message %#v to bridge", b.Account, msg)
|
|
|
|
}
|
2017-09-11 20:45:15 +00:00
|
|
|
// ignore delete messages
|
2018-11-15 19:43:43 +00:00
|
|
|
if msg.Event == config.EventMsgDelete {
|
2017-09-11 20:45:15 +00:00
|
|
|
return "", nil
|
|
|
|
}
|
2020-05-23 18:51:04 +00:00
|
|
|
|
2018-02-28 21:23:29 +00:00
|
|
|
b.Log.Debugf("=> Receiving %#v", msg)
|
2018-02-26 16:09:23 +00:00
|
|
|
|
2020-04-16 20:16:25 +00:00
|
|
|
if msg.Event == config.EventAvatarDownload {
|
|
|
|
return b.cacheAvatar(&msg), nil
|
|
|
|
}
|
|
|
|
|
2020-05-23 18:51:04 +00:00
|
|
|
// Make a action /me of the message, prepend the username with it.
|
|
|
|
// https://xmpp.org/extensions/xep-0245.html
|
|
|
|
if msg.Event == config.EventUserAction {
|
|
|
|
msg.Username = "/me " + msg.Username
|
|
|
|
}
|
|
|
|
|
2019-05-30 10:31:54 +00:00
|
|
|
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
|
2021-01-21 21:50:04 +00:00
|
|
|
var err error
|
2017-11-24 21:55:24 +00:00
|
|
|
if msg.Extra != nil {
|
2018-02-03 00:11:11 +00:00
|
|
|
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
2019-05-30 10:31:54 +00:00
|
|
|
b.Log.Debugf("=> Sending attachement message %#v", rmsg)
|
2021-01-21 21:50:04 +00:00
|
|
|
if b.GetString("WebhookURL") != "" {
|
|
|
|
err = b.postSlackCompatibleWebhook(msg)
|
|
|
|
} else {
|
|
|
|
_, err = b.xc.Send(xmpp.Chat{
|
|
|
|
Type: "groupchat",
|
|
|
|
Remote: rmsg.Channel + "@" + b.GetString("Muc"),
|
|
|
|
Text: rmsg.Username + rmsg.Text,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2019-05-30 10:31:54 +00:00
|
|
|
b.Log.WithError(err).Error("Unable to send message with share URL.")
|
|
|
|
}
|
2018-02-03 00:11:11 +00:00
|
|
|
}
|
2017-11-24 21:55:24 +00:00
|
|
|
if len(msg.Extra["file"]) > 0 {
|
2019-05-30 10:31:54 +00:00
|
|
|
return "", b.handleUploadFile(&msg)
|
2017-11-24 21:55:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-21 21:50:04 +00:00
|
|
|
if b.GetString("WebhookURL") != "" {
|
|
|
|
b.Log.Debugf("Sending message using Webhook")
|
|
|
|
err := b.postSlackCompatibleWebhook(msg)
|
|
|
|
if err != nil {
|
|
|
|
b.Log.Errorf("Failed to send message using webhook: %s", err)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Post normal message.
|
2019-05-30 10:31:54 +00:00
|
|
|
var msgReplaceID string
|
|
|
|
msgID := xid.New().String()
|
2018-05-29 21:29:51 +00:00
|
|
|
if msg.ID != "" {
|
2019-05-30 10:31:54 +00:00
|
|
|
msgID = msg.ID
|
|
|
|
msgReplaceID = msg.ID
|
2018-05-29 21:29:51 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
b.Log.Debugf("=> Sending message %#v", msg)
|
|
|
|
if _, err := b.xc.Send(xmpp.Chat{
|
|
|
|
Type: "groupchat",
|
|
|
|
Remote: msg.Channel + "@" + b.GetString("Muc"),
|
|
|
|
Text: msg.Username + msg.Text,
|
|
|
|
ID: msgID,
|
|
|
|
ReplaceID: msgReplaceID,
|
|
|
|
}); err != nil {
|
2018-02-26 16:09:23 +00:00
|
|
|
return "", err
|
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
return msgID, nil
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 21:50:04 +00:00
|
|
|
func (b *Bxmpp) postSlackCompatibleWebhook(msg config.Message) error {
|
|
|
|
type XMPPWebhook struct {
|
|
|
|
Username string `json:"username"`
|
|
|
|
Text string `json:"text"`
|
|
|
|
}
|
|
|
|
webhookBody, err := json.Marshal(XMPPWebhook{
|
|
|
|
Username: msg.Username,
|
|
|
|
Text: msg.Text,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
b.Log.Errorf("Failed to marshal webhook: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-17 20:30:06 +00:00
|
|
|
resp, err := http.Post(b.GetString("WebhookURL")+"/"+url.QueryEscape(msg.Channel), "application/json", bytes.NewReader(webhookBody))
|
2021-02-15 21:18:30 +00:00
|
|
|
if err != nil {
|
|
|
|
b.Log.Errorf("Failed to POST webhook: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-01-21 21:50:04 +00:00
|
|
|
resp.Body.Close()
|
2021-02-15 21:18:30 +00:00
|
|
|
return nil
|
2021-01-21 21:50:04 +00:00
|
|
|
}
|
|
|
|
|
2019-05-30 10:31:54 +00:00
|
|
|
func (b *Bxmpp) createXMPP() error {
|
2019-09-07 19:36:25 +00:00
|
|
|
if !strings.Contains(b.GetString("Jid"), "@") {
|
|
|
|
return fmt.Errorf("the Jid %s doesn't contain an @", b.GetString("Jid"))
|
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
tc := &tls.Config{
|
2019-06-13 23:10:43 +00:00
|
|
|
ServerName: strings.Split(b.GetString("Jid"), "@")[1],
|
2019-05-30 10:31:54 +00:00
|
|
|
InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
|
|
|
|
}
|
2020-03-28 22:05:59 +00:00
|
|
|
|
|
|
|
xmpp.DebugWriter = b.Log.Writer()
|
|
|
|
|
2016-08-14 19:48:51 +00:00
|
|
|
options := xmpp.Options{
|
2018-03-04 22:52:14 +00:00
|
|
|
Host: b.GetString("Server"),
|
|
|
|
User: b.GetString("Jid"),
|
|
|
|
Password: b.GetString("Password"),
|
|
|
|
NoTLS: true,
|
2020-11-13 22:59:05 +00:00
|
|
|
StartTLS: !b.GetBool("NoTLS"),
|
2018-03-04 22:52:14 +00:00
|
|
|
TLSConfig: tc,
|
|
|
|
Debug: b.GetBool("debug"),
|
2016-08-14 19:48:51 +00:00
|
|
|
Session: true,
|
|
|
|
Status: "",
|
|
|
|
StatusMessage: "",
|
|
|
|
Resource: "",
|
2020-11-13 22:59:05 +00:00
|
|
|
InsecureAllowUnencryptedAuth: b.GetBool("NoTLS"),
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
var err error
|
|
|
|
b.xc, err = options.NewClient()
|
2019-05-30 10:31:54 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bxmpp) manageConnection() {
|
2019-06-30 16:34:38 +00:00
|
|
|
b.setConnected(true)
|
2019-05-30 10:31:54 +00:00
|
|
|
initial := true
|
|
|
|
bf := &backoff.Backoff{
|
|
|
|
Min: time.Second,
|
|
|
|
Max: 5 * time.Minute,
|
|
|
|
Jitter: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main connection loop. Each iteration corresponds to a successful
|
|
|
|
// connection attempt and the subsequent handling of the connection.
|
|
|
|
for {
|
|
|
|
if initial {
|
|
|
|
initial = false
|
|
|
|
} else {
|
|
|
|
b.Remote <- config.Message{
|
|
|
|
Username: "system",
|
|
|
|
Text: "rejoin",
|
|
|
|
Channel: "",
|
|
|
|
Account: b.Account,
|
|
|
|
Event: config.EventRejoinChannels,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := b.handleXMPP(); err != nil {
|
|
|
|
b.Log.WithError(err).Error("Disconnected.")
|
2019-06-30 16:34:38 +00:00
|
|
|
b.setConnected(false)
|
2019-05-30 10:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reconnection loop using an exponential back-off strategy. We
|
|
|
|
// only break out of the loop if we have successfully reconnected.
|
|
|
|
for {
|
|
|
|
d := bf.Duration()
|
|
|
|
b.Log.Infof("Reconnecting in %s.", d)
|
|
|
|
time.Sleep(d)
|
|
|
|
|
|
|
|
b.Log.Infof("Reconnecting now.")
|
|
|
|
if err := b.createXMPP(); err == nil {
|
2019-06-30 16:34:38 +00:00
|
|
|
b.setConnected(true)
|
2019-05-30 10:31:54 +00:00
|
|
|
bf.Reset()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
b.Log.Warn("Failed to reconnect.")
|
|
|
|
}
|
|
|
|
}
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
|
2016-11-26 14:02:39 +00:00
|
|
|
func (b *Bxmpp) xmppKeepAlive() chan bool {
|
|
|
|
done := make(chan bool)
|
2016-08-14 19:48:51 +00:00
|
|
|
go func() {
|
|
|
|
ticker := time.NewTicker(90 * time.Second)
|
2016-11-26 14:02:39 +00:00
|
|
|
defer ticker.Stop()
|
2016-08-14 19:48:51 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
2018-02-26 23:33:21 +00:00
|
|
|
b.Log.Debugf("PING")
|
2019-05-30 10:31:54 +00:00
|
|
|
if err := b.xc.PingC2S("", ""); err != nil {
|
2018-02-26 23:33:21 +00:00
|
|
|
b.Log.Debugf("PING failed %#v", err)
|
2017-07-20 21:16:43 +00:00
|
|
|
}
|
2016-11-26 14:02:39 +00:00
|
|
|
case <-done:
|
|
|
|
return
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2016-11-26 14:02:39 +00:00
|
|
|
return done
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 16:09:23 +00:00
|
|
|
func (b *Bxmpp) handleXMPP() error {
|
2019-02-23 22:03:21 +00:00
|
|
|
b.startTime = time.Now()
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2016-11-26 14:02:39 +00:00
|
|
|
done := b.xmppKeepAlive()
|
|
|
|
defer close(done)
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2016-08-14 19:48:51 +00:00
|
|
|
for {
|
|
|
|
m, err := b.xc.Recv()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2016-08-14 19:48:51 +00:00
|
|
|
switch v := m.(type) {
|
|
|
|
case xmpp.Chat:
|
|
|
|
if v.Type == "groupchat" {
|
2018-03-04 22:52:14 +00:00
|
|
|
b.Log.Debugf("== Receiving %#v", v)
|
2019-05-30 10:31:54 +00:00
|
|
|
|
|
|
|
// Skip invalid messages.
|
2018-02-26 16:09:23 +00:00
|
|
|
if b.skipMessage(v) {
|
|
|
|
continue
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
|
|
|
var event string
|
2019-02-23 22:03:21 +00:00
|
|
|
if strings.Contains(v.Text, "has set the subject to:") {
|
|
|
|
event = config.EventTopicChange
|
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2020-05-24 12:07:36 +00:00
|
|
|
available, sok := b.avatarAvailability[v.Remote]
|
|
|
|
avatar := ""
|
|
|
|
if !sok {
|
2020-04-16 20:16:25 +00:00
|
|
|
b.Log.Debugf("Requesting avatar data")
|
2020-05-24 12:07:36 +00:00
|
|
|
b.avatarAvailability[v.Remote] = false
|
2020-04-16 20:16:25 +00:00
|
|
|
b.xc.AvatarRequestData(v.Remote)
|
2020-05-24 12:07:36 +00:00
|
|
|
} else if available {
|
|
|
|
avatar = getAvatar(b.avatarMap, v.Remote, b.General)
|
2020-04-16 20:16:25 +00:00
|
|
|
}
|
|
|
|
|
2019-05-30 10:31:54 +00:00
|
|
|
msgID := v.ID
|
2018-05-29 21:29:51 +00:00
|
|
|
if v.ReplaceID != "" {
|
2019-05-30 10:31:54 +00:00
|
|
|
msgID = v.ReplaceID
|
2018-05-29 21:29:51 +00:00
|
|
|
}
|
2019-02-23 22:03:21 +00:00
|
|
|
rmsg := config.Message{
|
|
|
|
Username: b.parseNick(v.Remote),
|
|
|
|
Text: v.Text,
|
|
|
|
Channel: b.parseChannel(v.Remote),
|
|
|
|
Account: b.Account,
|
2020-04-16 20:16:25 +00:00
|
|
|
Avatar: avatar,
|
2019-02-23 22:03:21 +00:00
|
|
|
UserID: v.Remote,
|
2019-05-30 10:31:54 +00:00
|
|
|
ID: msgID,
|
2019-02-23 22:03:21 +00:00
|
|
|
Event: event,
|
|
|
|
}
|
2018-02-26 16:09:23 +00:00
|
|
|
|
2019-05-30 10:31:54 +00:00
|
|
|
// Check if we have an action event.
|
|
|
|
var ok bool
|
2018-02-26 16:09:23 +00:00
|
|
|
rmsg.Text, ok = b.replaceAction(rmsg.Text)
|
|
|
|
if ok {
|
2018-11-15 19:43:43 +00:00
|
|
|
rmsg.Event = config.EventUserAction
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
2018-02-28 21:23:29 +00:00
|
|
|
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
|
|
|
|
b.Log.Debugf("<= Message is %#v", rmsg)
|
2018-02-26 16:09:23 +00:00
|
|
|
b.Remote <- rmsg
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
2020-04-16 20:16:25 +00:00
|
|
|
case xmpp.AvatarData:
|
|
|
|
b.handleDownloadAvatar(v)
|
2020-05-24 12:07:36 +00:00
|
|
|
b.avatarAvailability[v.From] = true
|
|
|
|
b.Log.Debugf("Avatar for %s is now available", v.From)
|
2016-08-14 19:48:51 +00:00
|
|
|
case xmpp.Presence:
|
2019-05-30 10:31:54 +00:00
|
|
|
// Do nothing.
|
2016-08-14 19:48:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-30 15:48:23 +00:00
|
|
|
|
|
|
|
func (b *Bxmpp) replaceAction(text string) (string, bool) {
|
|
|
|
if strings.HasPrefix(text, "/me ") {
|
|
|
|
return strings.Replace(text, "/me ", "", -1), true
|
|
|
|
}
|
|
|
|
return text, false
|
|
|
|
}
|
2018-02-26 16:09:23 +00:00
|
|
|
|
|
|
|
// handleUploadFile handles native upload of files
|
2019-05-30 10:31:54 +00:00
|
|
|
func (b *Bxmpp) handleUploadFile(msg *config.Message) error {
|
|
|
|
var urlDesc string
|
2018-05-29 21:29:51 +00:00
|
|
|
|
2019-05-30 10:31:54 +00:00
|
|
|
for _, file := range msg.Extra["file"] {
|
|
|
|
fileInfo := file.(config.FileInfo)
|
|
|
|
if fileInfo.Comment != "" {
|
|
|
|
msg.Text += fileInfo.Comment + ": "
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
if fileInfo.URL != "" {
|
|
|
|
msg.Text = fileInfo.URL
|
|
|
|
if fileInfo.Comment != "" {
|
|
|
|
msg.Text = fileInfo.Comment + ": " + fileInfo.URL
|
|
|
|
urlDesc = fileInfo.Comment
|
2018-05-06 14:57:59 +00:00
|
|
|
}
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
if _, err := b.xc.Send(xmpp.Chat{
|
|
|
|
Type: "groupchat",
|
|
|
|
Remote: msg.Channel + "@" + b.GetString("Muc"),
|
|
|
|
Text: msg.Username + msg.Text,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
|
|
|
|
if fileInfo.URL != "" {
|
|
|
|
if _, err := b.xc.SendOOB(xmpp.Chat{
|
|
|
|
Type: "groupchat",
|
|
|
|
Remote: msg.Channel + "@" + b.GetString("Muc"),
|
|
|
|
Ooburl: fileInfo.URL,
|
|
|
|
Oobdesc: urlDesc,
|
|
|
|
}); err != nil {
|
|
|
|
b.Log.WithError(err).Warn("Failed to send share URL.")
|
|
|
|
}
|
2018-05-09 21:04:10 +00:00
|
|
|
}
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
2019-05-30 10:31:54 +00:00
|
|
|
return nil
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bxmpp) parseNick(remote string) string {
|
|
|
|
s := strings.Split(remote, "@")
|
2021-07-20 21:39:14 +00:00
|
|
|
if len(s) > 1 {
|
2018-02-26 16:09:23 +00:00
|
|
|
s = strings.Split(s[1], "/")
|
|
|
|
if len(s) == 2 {
|
|
|
|
return s[1] // nick
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bxmpp) parseChannel(remote string) string {
|
|
|
|
s := strings.Split(remote, "@")
|
|
|
|
if len(s) >= 2 {
|
|
|
|
return s[0] // channel
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// skipMessage skips messages that need to be skipped
|
|
|
|
func (b *Bxmpp) skipMessage(message xmpp.Chat) bool {
|
|
|
|
// skip messages from ourselves
|
2018-03-04 22:52:14 +00:00
|
|
|
if b.parseNick(message.Remote) == b.GetString("Nick") {
|
2018-02-26 16:09:23 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip empty messages
|
|
|
|
if message.Text == "" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip subject messages
|
|
|
|
if strings.Contains(message.Text, "</subject>") {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-02-23 22:03:21 +00:00
|
|
|
// do not show subjects on connect #732
|
|
|
|
if strings.Contains(message.Text, "has set the subject to:") && time.Since(b.startTime) < time.Second*5 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-01-21 21:50:04 +00:00
|
|
|
// Ignore messages posted by our webhook
|
|
|
|
if b.GetString("WebhookURL") != "" && strings.Contains(message.ID, "webhookbot") {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-02-26 16:09:23 +00:00
|
|
|
// skip delayed messages
|
2019-06-13 22:44:31 +00:00
|
|
|
return !message.Stamp.IsZero() && time.Since(message.Stamp).Minutes() > 5
|
2018-02-26 16:09:23 +00:00
|
|
|
}
|
2019-06-30 16:34:38 +00:00
|
|
|
|
|
|
|
func (b *Bxmpp) setConnected(state bool) {
|
|
|
|
b.Lock()
|
|
|
|
b.connected = state
|
|
|
|
defer b.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Bxmpp) Connected() bool {
|
|
|
|
b.RLock()
|
|
|
|
defer b.RUnlock()
|
|
|
|
return b.connected
|
|
|
|
}
|