From 67a9d133e9cfef9317b3950383b6a48680998905 Mon Sep 17 00:00:00 2001 From: Wim Date: Sun, 3 Dec 2017 01:29:25 +0100 Subject: [PATCH] Add quick & dirty sshchat support (https://github.com/shazow/ssh-chat) --- bridge/bridge.go | 4 ++ bridge/config/config.go | 1 + bridge/sshchat/sshchat.go | 138 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 bridge/sshchat/sshchat.go diff --git a/bridge/bridge.go b/bridge/bridge.go index 5df7c3da..4c0540f6 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -10,6 +10,7 @@ import ( "github.com/42wim/matterbridge/bridge/mattermost" "github.com/42wim/matterbridge/bridge/rocketchat" "github.com/42wim/matterbridge/bridge/slack" + "github.com/42wim/matterbridge/bridge/sshchat" "github.com/42wim/matterbridge/bridge/steam" "github.com/42wim/matterbridge/bridge/telegram" "github.com/42wim/matterbridge/bridge/xmpp" @@ -79,6 +80,9 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid case "steam": b.Config = cfg.Steam[name] b.Bridger = bsteam.New(cfg.Steam[name], bridge.Account, c) + case "sshchat": + b.Config = cfg.Sshchat[name] + b.Bridger = bsshchat.New(cfg.Sshchat[name], bridge.Account, c) case "api": b.Config = cfg.Api[name] b.Bridger = api.New(cfg.Api[name], bridge.Account, c) diff --git a/bridge/config/config.go b/bridge/config/config.go index 47e2a1d6..6344fa59 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -141,6 +141,7 @@ type Config struct { Discord map[string]Protocol Telegram map[string]Protocol Rocketchat map[string]Protocol + Sshchat map[string]Protocol General Protocol Gateway []Gateway SameChannelGateway []SameChannelGateway diff --git a/bridge/sshchat/sshchat.go b/bridge/sshchat/sshchat.go new file mode 100644 index 00000000..becb688c --- /dev/null +++ b/bridge/sshchat/sshchat.go @@ -0,0 +1,138 @@ +package bsshchat + +import ( + "bufio" + "github.com/42wim/matterbridge/bridge/config" + log "github.com/Sirupsen/logrus" + "github.com/shazow/ssh-chat/sshd" + "io" + "strings" +) + +type Bsshchat struct { + r *bufio.Scanner + w io.WriteCloser + Config *config.Protocol + Remote chan config.Message + Account string +} + +var flog *log.Entry +var protocol = "sshchat" + +func init() { + flog = log.WithFields(log.Fields{"module": protocol}) +} + +func New(cfg config.Protocol, account string, c chan config.Message) *Bsshchat { + b := &Bsshchat{} + b.Config = &cfg + b.Account = account + b.Remote = c + return b +} + +func (b *Bsshchat) Connect() error { + var err error + flog.Infof("Connecting %s", b.Config.Server) + go func() { + err = sshd.ConnectShell(b.Config.Server, b.Config.Nick, func(r io.Reader, w io.WriteCloser) error { + b.r = bufio.NewScanner(r) + b.w = w + b.r.Scan() + w.Write([]byte("/theme mono\r\n")) + b.handleSshChat() + return nil + }) + }() + if err != nil { + flog.Debugf("%#v", err) + return err + } + flog.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.EVENT_MSG_DELETE { + return "", nil + } + flog.Debugf("Receiving %#v", msg) + if msg.Extra != nil { + if len(msg.Extra["file"]) > 0 { + for _, f := range msg.Extra["file"] { + fi := f.(config.FileInfo) + if fi.URL != "" { + msg.Text = fi.URL + } + b.w.Write([]byte(msg.Username + msg.Text)) + } + return "", nil + } + } + b.w.Write([]byte(msg.Username + msg.Text + "\r\n")) + return "", nil +} + +/* +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: + flog.Debugf("PING") + err := b.xc.PingC2S("", "") + if err != nil { + flog.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() { + res := strings.Split(stripPrompt(b.r.Text()), ":") + if res[0] == "-> Set theme" { + wait = false + log.Debugf("mono found, allowing") + continue + } + if !wait { + flog.Debugf("message %#v", res) + rmsg := config.Message{Username: res[0], Text: strings.Join(res[1:], ":"), Channel: "sshchat", Account: b.Account, UserID: "nick"} + b.Remote <- rmsg + } + } + } +}