summaryrefslogtreecommitdiffstats
path: root/bridge/xmpp/xmpp.go
blob: 5d10f9bd21099857af130803dc8175e8d11cc655 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package bxmpp

import (
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/mattn/go-xmpp"

	"strings"
	"time"
)

type Bxmpp struct {
	xc      *xmpp.Client
	xmppMap map[string]string
	*config.Config
	Remote chan config.Message
}

type FancyLog struct {
	xmpp *log.Entry
}

type Message struct {
	Text     string
	Channel  string
	Username string
}

var flog FancyLog

func init() {
	flog.xmpp = log.WithFields(log.Fields{"module": "xmpp"})
}

func New(config *config.Config, c chan config.Message) *Bxmpp {
	b := &Bxmpp{}
	b.xmppMap = make(map[string]string)
	b.Config = config
	b.Remote = c
	return b
}

func (b *Bxmpp) Connect() error {
	var err error
	flog.xmpp.Info("Trying XMPP connection")
	b.xc, err = b.createXMPP()
	if err != nil {
		flog.xmpp.Debugf("%#v", err)
		return err
	}
	flog.xmpp.Info("Connection succeeded")
	b.setupChannels()
	go b.handleXmpp()
	return nil
}

func (b *Bxmpp) Name() string {
	return "xmpp"
}

func (b *Bxmpp) Send(msg config.Message) error {
	username := msg.Username + ": "
	if b.Config.Xmpp.RemoteNickFormat != "" {
		username = strings.Replace(b.Config.Xmpp.RemoteNickFormat, "{NICK}", msg.Username, -1)
	}
	b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Xmpp.Muc, Text: username + msg.Text})
	return nil
}

func (b *Bxmpp) createXMPP() (*xmpp.Client, error) {
	options := xmpp.Options{
		Host:     b.Config.Xmpp.Server,
		User:     b.Config.Xmpp.Jid,
		Password: b.Config.Xmpp.Password,
		NoTLS:    true,
		StartTLS: true,
		//StartTLS:      false,
		Debug:                        true,
		Session:                      true,
		Status:                       "",
		StatusMessage:                "",
		Resource:                     "",
		InsecureAllowUnencryptedAuth: false,
		//InsecureAllowUnencryptedAuth: true,
	}
	var err error
	b.xc, err = options.NewClient()
	return b.xc, err
}

func (b *Bxmpp) setupChannels() {
	for _, val := range b.Config.Channel {
		flog.xmpp.Infof("Joining %s as %s", val.Xmpp, b.Xmpp.Nick)
		b.xc.JoinMUCNoHistory(val.Xmpp+"@"+b.Xmpp.Muc, b.Xmpp.Nick)
	}
}

func (b *Bxmpp) xmppKeepAlive() {
	go func() {
		ticker := time.NewTicker(90 * time.Second)
		for {
			select {
			case <-ticker.C:
				b.xc.Send(xmpp.Chat{})
			}
		}
	}()
}

func (b *Bxmpp) handleXmpp() error {
	for {
		m, err := b.xc.Recv()
		if err != nil {
			return err
		}
		switch v := m.(type) {
		case xmpp.Chat:
			var channel, nick string
			if v.Type == "groupchat" {
				s := strings.Split(v.Remote, "@")
				if len(s) == 2 {
					channel = s[0]
				}
				s = strings.Split(s[1], "/")
				if len(s) == 2 {
					nick = s[1]
				}
				if nick != b.Xmpp.Nick {
					flog.xmpp.Info("sending message to remote", nick, v.Text, channel)
					b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Origin: "xmpp"}
				}
			}
		case xmpp.Presence:
			// do nothing
		}
	}
}