mirror of
https://github.com/cwinfo/matterbridge.git
synced 2024-11-14 15:30:27 +00:00
170 lines
3.9 KiB
Go
170 lines
3.9 KiB
Go
package bsshchat
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/42wim/matterbridge/bridge"
|
|
"github.com/42wim/matterbridge/bridge/config"
|
|
"github.com/42wim/matterbridge/bridge/helper"
|
|
"github.com/shazow/ssh-chat/sshd"
|
|
)
|
|
|
|
type Bsshchat struct {
|
|
r *bufio.Scanner
|
|
w io.WriteCloser
|
|
*bridge.Config
|
|
}
|
|
|
|
func New(cfg *bridge.Config) bridge.Bridger {
|
|
return &Bsshchat{Config: cfg}
|
|
}
|
|
|
|
func (b *Bsshchat) Connect() error {
|
|
b.Log.Infof("Connecting %s", b.GetString("Server"))
|
|
|
|
// connHandler will be called by 'sshd.ConnectShell()' below
|
|
// once the connection is established in order to handle it.
|
|
connErr := make(chan error, 1) // Needs to be buffered.
|
|
connSignal := make(chan struct{})
|
|
connHandler := func(r io.Reader, w io.WriteCloser) error {
|
|
b.r = bufio.NewScanner(r)
|
|
b.r.Scan()
|
|
b.w = w
|
|
if _, err := b.w.Write([]byte("/theme mono\r\n/quiet\r\n")); err != nil {
|
|
return err
|
|
}
|
|
close(connSignal) // Connection is established so we can signal the success.
|
|
return b.handleSSHChat()
|
|
}
|
|
|
|
go func() {
|
|
// As a successful connection will result in this returning after the Connection
|
|
// method has already returned point we NEED to have a buffered channel to still
|
|
// be able to write.
|
|
connErr <- sshd.ConnectShell(b.GetString("Server"), b.GetString("Nick"), connHandler)
|
|
}()
|
|
|
|
select {
|
|
case err := <-connErr:
|
|
b.Log.Error("Connection failed")
|
|
return err
|
|
case <-connSignal:
|
|
}
|
|
b.Log.Info("Connection succeeded")
|
|
return nil
|
|
}
|
|
|
|
func (b *Bsshchat) Disconnect() error {
|
|
return nil
|
|
}
|
|
|
|
func (b *Bsshchat) JoinChannel(channel config.ChannelInfo) error {
|
|
return nil
|
|
}
|
|
|
|
func (b *Bsshchat) Send(msg config.Message) (string, error) {
|
|
// ignore delete messages
|
|
if msg.Event == config.EventMsgDelete {
|
|
return "", nil
|
|
}
|
|
b.Log.Debugf("=> Receiving %#v", msg)
|
|
if msg.Extra != nil {
|
|
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
|
if _, err := b.w.Write([]byte(rmsg.Username + rmsg.Text + "\r\n")); err != nil {
|
|
b.Log.Errorf("Could not send extra message: %#v", err)
|
|
}
|
|
}
|
|
if len(msg.Extra["file"]) > 0 {
|
|
return b.handleUploadFile(&msg)
|
|
}
|
|
}
|
|
_, err := b.w.Write([]byte(msg.Username + msg.Text + "\r\n"))
|
|
return "", err
|
|
}
|
|
|
|
/*
|
|
func (b *Bsshchat) sshchatKeepAlive() chan bool {
|
|
done := make(chan bool)
|
|
go func() {
|
|
ticker := time.NewTicker(90 * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
b.Log.Debugf("PING")
|
|
err := b.xc.PingC2S("", "")
|
|
if err != nil {
|
|
b.Log.Debugf("PING failed %#v", err)
|
|
}
|
|
case <-done:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
return done
|
|
}
|
|
*/
|
|
|
|
func stripPrompt(s string) string {
|
|
pos := strings.LastIndex(s, "\033[K")
|
|
if pos < 0 {
|
|
return s
|
|
}
|
|
return s[pos+3:]
|
|
}
|
|
|
|
func (b *Bsshchat) handleSSHChat() error {
|
|
/*
|
|
done := b.sshchatKeepAlive()
|
|
defer close(done)
|
|
*/
|
|
wait := true
|
|
for {
|
|
if b.r.Scan() {
|
|
// ignore messages from ourselves
|
|
if !strings.Contains(b.r.Text(), "\033[K") {
|
|
continue
|
|
}
|
|
if strings.Contains(b.r.Text(), "Rate limiting is in effect") {
|
|
continue
|
|
}
|
|
// skip our own messages
|
|
if !strings.HasPrefix(b.r.Text(), "["+b.GetString("Nick")+"] \x1b") {
|
|
continue
|
|
}
|
|
res := strings.Split(stripPrompt(b.r.Text()), ":")
|
|
if res[0] == "-> Set theme" {
|
|
wait = false
|
|
b.Log.Debugf("mono found, allowing")
|
|
continue
|
|
}
|
|
if !wait {
|
|
b.Log.Debugf("<= Message %#v", res)
|
|
rmsg := config.Message{Username: res[0], Text: strings.TrimSpace(strings.Join(res[1:], ":")), Channel: "sshchat", Account: b.Account, UserID: "nick"}
|
|
b.Remote <- rmsg
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (b *Bsshchat) handleUploadFile(msg *config.Message) (string, error) {
|
|
for _, f := range msg.Extra["file"] {
|
|
fi := f.(config.FileInfo)
|
|
if fi.Comment != "" {
|
|
msg.Text += fi.Comment + ": "
|
|
}
|
|
if fi.URL != "" {
|
|
msg.Text = fi.URL
|
|
if fi.Comment != "" {
|
|
msg.Text = fi.Comment + ": " + fi.URL
|
|
}
|
|
}
|
|
if _, err := b.w.Write([]byte(msg.Username + msg.Text + "\r\n")); err != nil {
|
|
b.Log.Errorf("Could not send file message: %#v", err)
|
|
}
|
|
}
|
|
return "", nil
|
|
}
|