diff --git a/build.sh b/build.sh index 2d8f2e83..11e0b9d2 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ #!/bin/bash -env GOPATH="$PWD" go build +env GOPATH="$PWD" go install ergonomadic diff --git a/ergonomadic.go b/src/ergonomadic/ergonomadic.go similarity index 100% rename from ergonomadic.go rename to src/ergonomadic/ergonomadic.go diff --git a/src/irc/client.go b/src/irc/client.go index b24b07a1..5eacc0d0 100644 --- a/src/irc/client.go +++ b/src/irc/client.go @@ -2,6 +2,7 @@ package irc import ( "fmt" + "log" "net" ) @@ -16,9 +17,9 @@ type Client struct { hostname string nick string serverPass bool + registered bool // modes away bool - registered bool invisible bool wallOps bool restricted bool @@ -48,7 +49,9 @@ func (c *Client) SetReplyToStringChan() { write := StringWriteChan(c.conn) go func() { for reply := range send { - write <- reply.String(c) + replyStr := reply.String(c) + log.Printf("%s <- %s", c.Id(), replyStr) + write <- replyStr } }() c.send = send @@ -88,8 +91,15 @@ func (c *Client) HasUser() bool { return c.username != "" } +func (c *Client) Username() string { + if c.HasUser() { + return c.username + } + return "*" +} + func (c *Client) UserHost() string { - return fmt.Sprintf("%s!%s@%s", c.nick, c.username, c.hostname) + return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Username(), c.hostname) } func (c *Client) Id() string { diff --git a/src/irc/commands.go b/src/irc/commands.go index e59004d1..908a27ee 100644 --- a/src/irc/commands.go +++ b/src/irc/commands.go @@ -21,6 +21,7 @@ var ( type UnknownMessage struct { command string + args []string } // NB: no constructor, created on demand in parser for invalid messages. @@ -83,14 +84,16 @@ func NewPassMessage(args []string) (Message, error) { if len(args) < 1 { return nil, NotEnoughArgsError } - return &PassMessage{password: args[0]} + return &PassMessage{ + password: args[0], + }, nil } func (m *PassMessage) Handle(s *Server, c *Client) { - if m.password == server.password { + if m.password == s.password { c.serverPass = true } else { - c.send <- ErrPass + c.send <- ErrPasswdMismatch(s) } } @@ -181,11 +184,9 @@ func NewModeMessage(args []string) (Message, error) { return nil, NotEnoughArgsError } - msg := &ModeMessage{ - nickname: args[0], - } if (len(args) > 1) && CHANNEL_RE.MatchString(args[1]) { - cmsg := &ChannelModeMessage{msg} + cmsg := new(ChannelModeMessage) + cmsg.nickname = args[0] if len(args) > 2 { groups := EXTRACT_MODE_RE.FindStringSubmatch(args[2]) cmsg.modes = make([]string, len(groups[2])) @@ -195,14 +196,18 @@ func NewModeMessage(args []string) (Message, error) { i++ } } - if len(args > 3) { + if len(args) > 3 { cmsg.modeParams = strings.Split(args[3], ",") } - return cmsg + return cmsg, nil + } + + msg := &ModeMessage{ + nickname: args[0], } for _, arg := range args[1:] { if !MODE_RE.MatchString(arg) { - return nil, ErrUModeUnknownFlag + return nil, UModeUnknownFlagError } prefix := arg[0] for _, c := range arg[1:] { @@ -407,14 +412,14 @@ type OperMessage struct { password string } -func NewOperMessage(args []string) Message { +func NewOperMessage(args []string) (Message, error) { if len(args) < 2 { return nil, NotEnoughArgsError } return &OperMessage{ name: args[0], password: args[1], - } + }, nil } func (m *OperMessage) Handle(s *Server, c *Client) { diff --git a/src/irc/net.go b/src/irc/net.go index c546e201..65e3f2a9 100644 --- a/src/irc/net.go +++ b/src/irc/net.go @@ -2,31 +2,29 @@ package irc import ( "bufio" - "log" "net" "strings" ) func readTrimmedLine(reader *bufio.Reader) (string, error) { line, err := reader.ReadString('\n') - return strings.TrimSpace(line), err + if err != nil { + return "", err + } + return strings.TrimSpace(line), nil } // Adapt `net.Conn` to a `chan string`. func StringReadChan(conn net.Conn) <-chan string { ch := make(chan string) reader := bufio.NewReader(conn) - addr := conn.RemoteAddr() go func() { for { line, err := readTrimmedLine(reader) - if line != "" { - ch <- line - log.Printf("%s -> %s", addr, line) - } if err != nil { break } + ch <- line } close(ch) }() @@ -36,14 +34,12 @@ func StringReadChan(conn net.Conn) <-chan string { func StringWriteChan(conn net.Conn) chan<- string { ch := make(chan string) writer := bufio.NewWriter(conn) - addr := conn.RemoteAddr() go func() { for str := range ch { - if _, err := writer.WriteString(str + "\r\n"); err != nil { + if _, err := writer.WriteString(str); err != nil { break } writer.Flush() - log.Printf("%s <- %s", addr, str) } close(ch) }() diff --git a/src/irc/parse.go b/src/irc/parse.go index b2835a78..b9bc6804 100644 --- a/src/irc/parse.go +++ b/src/irc/parse.go @@ -26,15 +26,13 @@ var ( } ) -func ParseMessage(line string) (msg Message, err error) { +func ParseMessage(line string) (Message, error) { command, args := parseLine(line) constructor, ok := parseCommandFuncs[command] if !ok { - msg = &UnknownMessage{command} - return + return &UnknownMessage{command, args}, nil } - msg, err = constructor(args) - return + return constructor(args) } func parseArg(line string) (arg string, rest string) { diff --git a/src/irc/reply.go b/src/irc/reply.go index dc155706..d1c43506 100644 --- a/src/irc/reply.go +++ b/src/irc/reply.go @@ -21,8 +21,8 @@ type BasicReply struct { } func (reply *BasicReply) String(client *Client) string { - prefix := fmt.Sprintf(":%s %s %s ", reply.source.Id(), reply.code, client.Nick()) - return prefix + reply.message + return fmt.Sprintf(":%s %s %s %s\r\n", reply.source.Id(), reply.code, client.Nick(), + reply.message) } type ChannelReply struct { @@ -31,8 +31,8 @@ type ChannelReply struct { } func (reply *ChannelReply) String(client *Client) string { - prefix := fmt.Sprintf(":%s %s %s ", reply.source.Id(), reply.code, reply.channel.name) - return prefix + reply.message + return fmt.Sprintf(":%s %s %s %s\r\n", reply.source.Id(), reply.code, reply.channel.name, + reply.message) } func NewReply(source Identifier, code string, message string) *BasicReply { @@ -99,11 +99,11 @@ func RplPart(channel *Channel, client *Client, message string) Reply { } func RplNoTopic(channel *Channel) Reply { - return &ChannelReply{NewReply(channel.server, RPL_NOTOPIC, ":No topic is set"), channel} + return NewReply(channel.server, RPL_NOTOPIC, channel.name+" :No topic is set") } func RplTopic(channel *Channel) Reply { - return &ChannelReply{NewReply(channel.server, RPL_TOPIC, ":"+channel.topic), channel} + return NewReply(channel.server, RPL_TOPIC, fmt.Sprintf("%s :%s", channel.name, channel.topic)) } // server info @@ -119,7 +119,7 @@ func RplEndOfNames(source Identifier) Reply { } func RplPong(server *Server) Reply { - return NewReply(server, RPL_PONG, "") + return NewReply(server, RPL_PONG, server.Id()) } // server functions diff --git a/src/irc/server.go b/src/irc/server.go index 90b0fe62..082f2fcb 100644 --- a/src/irc/server.go +++ b/src/irc/server.go @@ -33,6 +33,7 @@ func NewServer(name string) *Server { } go func() { for m := range recv { + log.Printf("%s -> %T%+v", m.client.Id(), m.message, m.message) m.message.Handle(server, m.client) } }() @@ -120,7 +121,7 @@ func (s *Server) UserLogin(c *Client, user string, realName string) { } func (s *Server) tryRegister(c *Client) { - if !c.registered && c.HasNick() && c.HasUser() && (s.password == "" || c.serverAuth) { + if !c.registered && c.HasNick() && c.HasUser() && (s.password == "" || c.serverPass) { c.registered = true c.send <- RplWelcome(s, c) c.send <- RplYourHost(s, c)