From eda2b7c0d930fcfd4436ce39f9a5573d3e103fa8 Mon Sep 17 00:00:00 2001
From: Andrey Petrov <andrey.petrov@shazow.net>
Date: Mon, 22 Dec 2014 22:21:07 -0800
Subject: [PATCH] Super broken but kinda working.

---
 chat/channel.go      | 12 +++++---
 chat/channel_test.go |  2 +-
 chat/command.go      |  8 +++---
 chat/host.go         | 28 -------------------
 chat/message.go      | 11 ++++++--
 cmd.go               | 65 ++++++++++++++++++++++++++++++++++----------
 sshd/doc.go          |  3 +-
 7 files changed, 75 insertions(+), 54 deletions(-)
 delete mode 100644 chat/host.go

diff --git a/chat/channel.go b/chat/channel.go
index 180dada..b52fb47 100644
--- a/chat/channel.go
+++ b/chat/channel.go
@@ -7,7 +7,6 @@ const channelBuffer = 10
 
 // Channel definition, also a Set of User Items
 type Channel struct {
-	id        string
 	topic     string
 	history   *History
 	users     *Set
@@ -15,11 +14,10 @@ type Channel struct {
 }
 
 // Create new channel and start broadcasting goroutine.
-func NewChannel(id string) *Channel {
+func NewChannel() *Channel {
 	broadcast := make(chan Message, channelBuffer)
 
 	ch := Channel{
-		id:        id,
 		broadcast: broadcast,
 		history:   NewHistory(historyLen),
 		users:     NewSet(),
@@ -27,8 +25,14 @@ func NewChannel(id string) *Channel {
 
 	go func() {
 		for m := range broadcast {
+			// TODO: Handle commands etc?
 			ch.users.Each(func(u Item) {
-				u.(*User).Send(m)
+				user := u.(*User)
+				if m.from == user {
+					// Skip
+					return
+				}
+				user.Send(m)
 			})
 		}
 	}()
diff --git a/chat/channel_test.go b/chat/channel_test.go
index f261081..3e16030 100644
--- a/chat/channel_test.go
+++ b/chat/channel_test.go
@@ -11,7 +11,7 @@ func TestChannel(t *testing.T) {
 	s := &MockScreen{}
 	u := NewUser("foo")
 
-	ch := NewChannel("")
+	ch := NewChannel()
 	defer ch.Close()
 
 	err := ch.Join(u)
diff --git a/chat/command.go b/chat/command.go
index 73ffa2f..896e524 100644
--- a/chat/command.go
+++ b/chat/command.go
@@ -8,7 +8,7 @@ import (
 var ErrInvalidCommand error = errors.New("invalid command")
 var ErrNoOwner error = errors.New("command without owner")
 
-type CmdHandler func(host Host, msg Message, args []string) error
+type CmdHandler func(msg Message, args []string) error
 
 type Commands map[string]CmdHandler
 
@@ -18,7 +18,7 @@ func (c Commands) Add(cmd string, handler CmdHandler) {
 }
 
 // Execute command message, assumes IsCommand was checked
-func (c Commands) Run(host Host, msg Message) error {
+func (c Commands) Run(msg Message) error {
 	if msg.from == nil {
 		return ErrNoOwner
 	}
@@ -29,7 +29,7 @@ func (c Commands) Run(host Host, msg Message) error {
 		return ErrInvalidCommand
 	}
 
-	return handler(host, msg, args)
+	return handler(msg, args)
 }
 
 var defaultCmdHandlers Commands
@@ -37,7 +37,7 @@ var defaultCmdHandlers Commands
 func init() {
 	c := Commands{}
 
-	c.Add("me", func(host Host, msg Message, args []string) error {
+	c.Add("me", func(msg Message, args []string) error {
 		me := strings.TrimLeft(msg.Body, "/me")
 		if me == "" {
 			me = " is at a loss for words."
diff --git a/chat/host.go b/chat/host.go
deleted file mode 100644
index 9834ed4..0000000
--- a/chat/host.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package chat
-
-// Host knows about all the commands and channels.
-type Host struct {
-	defaultChannel *Channel
-	commands       Commands
-	done           chan struct{}
-}
-
-func NewHost() *Host {
-	h := Host{
-		commands: defaultCmdHandlers,
-	}
-	h.defaultChannel = h.CreateChannel("")
-	return &h
-}
-
-func (h *Host) handleCommand(m Message) {
-	// TODO: ...
-}
-
-func (h *Host) broadcast(ch *Channel, m Message) {
-	// TODO: ...
-}
-
-func (h *Host) CreateChannel(id string) *Channel {
-	return NewChannel(id)
-}
diff --git a/chat/message.go b/chat/message.go
index aee5d38..5281b1a 100644
--- a/chat/message.go
+++ b/chat/message.go
@@ -9,8 +9,9 @@ import (
 // Container for messages sent to chat
 type Message struct {
 	Body       string
-	from       *User // Not set for Sys messages
-	to         *User // Only set for PMs
+	from       *User    // Not set for Sys messages
+	to         *User    // Only set for PMs
+	channel    *Channel // Not set for global commands
 	timestamp  time.Time
 	themeCache *map[*Theme]string
 }
@@ -35,6 +36,12 @@ func (m *Message) From(u *User) *Message {
 	return m
 }
 
+// Set channel
+func (m *Message) Channel(ch *Channel) *Message {
+	m.channel = ch
+	return m
+}
+
 // Render message based on the given theme
 func (m *Message) Render(*Theme) string {
 	// TODO: Return []byte?
diff --git a/cmd.go b/cmd.go
index 89ad01a..6491cdc 100644
--- a/cmd.go
+++ b/cmd.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"bufio"
 	"fmt"
 	"io/ioutil"
 	"net/http"
@@ -13,6 +12,10 @@ import (
 	"github.com/alexcesaro/log"
 	"github.com/alexcesaro/log/golog"
 	"github.com/jessevdk/go-flags"
+	"golang.org/x/crypto/ssh"
+
+	"github.com/shazow/ssh-chat/chat"
+	"github.com/shazow/ssh-chat/sshd"
 )
 import _ "net/http/pprof"
 
@@ -52,9 +55,6 @@ func main() {
 		}()
 	}
 
-	// Initialize seed for random colors
-	RandomColorInit()
-
 	// Figure out the log level
 	numVerbose := len(options.Verbose)
 	if numVerbose > len(logLevels) {
@@ -78,12 +78,55 @@ func main() {
 		return
 	}
 
-	server, err := NewServer(privateKey)
+	signer, err := ssh.ParsePrivateKey(privateKey)
 	if err != nil {
-		logger.Errorf("Failed to create server: %v", err)
+		logger.Errorf("Failed to prase key: %v", err)
 		return
 	}
 
+	// TODO: MakeAuth
+	config := sshd.MakeNoAuth()
+	config.AddHostKey(signer)
+
+	s, err := sshd.ListenSSH(options.Bind, config)
+	if err != nil {
+		logger.Errorf("Failed to listen on socket: %v", err)
+		return
+	}
+	defer s.Close()
+
+	terminals := s.ServeTerminal()
+	channel := chat.NewChannel()
+
+	// TODO: Move this elsewhere
+	go func() {
+		for term := range terminals {
+			go func() {
+				defer term.Close()
+				name := term.Conn.User()
+				term.SetPrompt(fmt.Sprintf("[%s]", name))
+				// TODO: term.AutoCompleteCallback = ...
+				user := chat.NewUserScreen(name, term)
+				channel.Join(user)
+
+				for {
+					// TODO: Handle commands etc?
+					line, err := term.ReadLine()
+					if err != nil {
+						break
+					}
+					m := chat.NewMessage(line).From(user)
+					channel.Send(*m)
+				}
+
+				// TODO: Handle disconnect sooner (currently closes channel before removing)
+				channel.Leave(user)
+				user.Close()
+			}()
+		}
+	}()
+
+	/* TODO:
 	for _, fingerprint := range options.Admin {
 		server.Op(fingerprint)
 	}
@@ -109,23 +152,17 @@ func main() {
 			return
 		}
 		motdString := string(motd[:])
-		/* hack to normalize line endings into \r\n */
+		// hack to normalize line endings into \r\n
 		motdString = strings.Replace(motdString, "\r\n", "\n", -1)
 		motdString = strings.Replace(motdString, "\n", "\r\n", -1)
 		server.SetMotd(motdString)
 	}
+	*/
 
 	// Construct interrupt handler
 	sig := make(chan os.Signal, 1)
 	signal.Notify(sig, os.Interrupt)
 
-	err = server.Start(options.Bind)
-	if err != nil {
-		logger.Errorf("Failed to start server: %v", err)
-		return
-	}
-
 	<-sig // Wait for ^C signal
 	logger.Warningf("Interrupt signal detected, shutting down.")
-	server.Stop()
 }
diff --git a/sshd/doc.go b/sshd/doc.go
index 4d94d8b..aacbcac 100644
--- a/sshd/doc.go
+++ b/sshd/doc.go
@@ -11,6 +11,7 @@ package sshd
 	if err != nil {
 		// Handle opening socket error
 	}
+	defer s.Close()
 
 	terminals := s.ServeTerminal()
 
@@ -21,7 +22,7 @@ package sshd
 			term.AutoCompleteCallback = nil // ...
 
 			for {
-				line, err := term.Readline()
+				line, err := term.ReadLine()
 				if err != nil {
 					break
 				}