1
0
Fork 0
forked from External/ergo

Merge pull request #8 from jlatt/cap-protocol

basic capability negotiation
This commit is contained in:
Jeremy Latt 2014-03-06 17:39:12 -08:00
commit 4bcd42ff34
7 changed files with 222 additions and 101 deletions

View file

@ -29,7 +29,6 @@ type Server struct {
operators map[string][]byte
password []byte
signals chan os.Signal
timeout chan *Client
}
func NewServer(config *Config) *Server {
@ -45,7 +44,6 @@ func NewServer(config *Config) *Server {
newConns: make(chan net.Conn, 16),
operators: config.Operators(),
signals: make(chan os.Signal, 1),
timeout: make(chan *Client, 16),
}
if config.Server.Password != "" {
@ -97,14 +95,6 @@ func (server *Server) processCommand(cmd Command) {
}
switch client.phase {
case Authorization:
authCmd, ok := cmd.(AuthServerCommand)
if !ok {
client.Quit("unexpected command")
return
}
authCmd.HandleAuthServer(server)
case Registration:
regCmd, ok := cmd.(RegServerCommand)
if !ok {
@ -113,7 +103,7 @@ func (server *Server) processCommand(cmd Command) {
}
regCmd.HandleRegServer(server)
default:
case Normal:
srvCmd, ok := cmd.(ServerCommand)
if !ok {
client.ErrUnknownCommand(cmd.Code())
@ -157,20 +147,10 @@ func (server *Server) Run() {
case client := <-server.idle:
client.Idle()
case client := <-server.timeout:
client.Quit("connection timeout")
}
}
}
func (server *Server) InitPhase() Phase {
if server.password == nil {
return Registration
}
return Authorization
}
//
// listen goroutine
//
@ -206,7 +186,7 @@ func (s *Server) listen(addr string) {
//
func (s *Server) tryRegister(c *Client) {
if c.HasNick() && c.HasUsername() {
if c.HasNick() && c.HasUsername() && (c.capState != CapNegotiating) {
c.Register()
c.RplWelcome()
c.RplYourHost()
@ -266,18 +246,10 @@ func (s *Server) Nick() string {
}
//
// authorization commands
// registration commands
//
func (msg *ProxyCommand) HandleAuthServer(server *Server) {
msg.Client().hostname = msg.hostname
}
func (msg *CapCommand) HandleAuthServer(server *Server) {
// TODO
}
func (msg *PassCommand) HandleAuthServer(server *Server) {
func (msg *PassCommand) HandleRegServer(server *Server) {
client := msg.Client()
if msg.err != nil {
client.ErrPasswdMismatch()
@ -285,27 +257,70 @@ func (msg *PassCommand) HandleAuthServer(server *Server) {
return
}
client.phase = Registration
client.authorized = true
}
func (msg *QuitCommand) HandleAuthServer(server *Server) {
msg.Client().Quit(msg.message)
}
//
// registration commands
//
func (msg *ProxyCommand) HandleRegServer(server *Server) {
msg.Client().hostname = msg.hostname
}
func (msg *CapCommand) HandleRegServer(server *Server) {
// TODO
client := msg.Client()
switch msg.subCommand {
case CAP_LS:
client.capState = CapNegotiating
client.Reply("CAP LS * :%s", SupportedCapabilities)
case CAP_LIST:
client.Reply("CAP LIST * :%s", client.capabilities)
case CAP_REQ:
client.capState = CapNegotiating
for capability := range msg.capabilities {
if !SupportedCapabilities[capability] {
client.Reply("CAP NAK * :%s", msg.capabilities)
return
}
}
for capability := range msg.capabilities {
client.capabilities[capability] = true
}
client.Reply("CAP ACK * :%s", msg.capabilities)
case CAP_CLEAR:
format := strings.TrimRight(
strings.Repeat("%s%s ", len(client.capabilities)), " ")
args := make([]interface{}, len(client.capabilities))
index := 0
for capability := range client.capabilities {
args[index] = Disable
args[index+1] = capability
index += 2
delete(client.capabilities, capability)
}
client.Reply("CAP ACK * :"+format, args...)
case CAP_END:
client.capState = CapNegotiated
server.tryRegister(client)
default:
client.ErrInvalidCapCmd(msg.subCommand)
}
}
func (m *NickCommand) HandleRegServer(s *Server) {
client := m.Client()
if !client.authorized {
client.ErrPasswdMismatch()
client.Quit("bad password")
return
}
if client.capState == CapNegotiating {
client.capState = CapNegotiated
}
if m.nickname == "" {
client.ErrNoNicknameGiven()
@ -327,11 +342,22 @@ func (m *NickCommand) HandleRegServer(s *Server) {
}
func (msg *RFC1459UserCommand) HandleRegServer(server *Server) {
client := msg.Client()
if !client.authorized {
client.ErrPasswdMismatch()
client.Quit("bad password")
return
}
msg.HandleRegServer2(server)
}
func (msg *RFC2812UserCommand) HandleRegServer(server *Server) {
client := msg.Client()
if !client.authorized {
client.ErrPasswdMismatch()
client.Quit("bad password")
return
}
flags := msg.Flags()
if len(flags) > 0 {
for _, mode := range msg.Flags() {
@ -344,6 +370,9 @@ func (msg *RFC2812UserCommand) HandleRegServer(server *Server) {
func (msg *UserCommand) HandleRegServer2(server *Server) {
client := msg.Client()
if client.capState == CapNegotiating {
client.capState = CapNegotiated
}
client.username, client.realname = msg.username, msg.realname
server.tryRegister(client)
}