diff --git a/ergonomadic.go b/ergonomadic.go index f2d5c1e3..457a8f53 100644 --- a/ergonomadic.go +++ b/ergonomadic.go @@ -6,7 +6,7 @@ import ( ) func main() { - name := flag.String("name", "localhost", "A name for the server") + name := flag.String("name", "ergonomadic", "A name for the server") listen := flag.String("listen", ":6667", "interface to listen on") flag.BoolVar(&irc.DEBUG_NET, "dnet", false, "debug net") flag.BoolVar(&irc.DEBUG_CLIENT, "dclient", false, "debug client") diff --git a/irc/client.go b/irc/client.go index ff1b0d8f..ee898c87 100644 --- a/irc/client.go +++ b/irc/client.go @@ -13,6 +13,7 @@ type Client struct { channels ChannelSet conn net.Conn hostname string + invisible bool nick string realname string registered bool @@ -30,11 +31,12 @@ func NewClient(server *Server, conn net.Conn) *Client { replies := make(chan Reply) client := &Client{ - channels: make(ChannelSet), - conn: conn, - hostname: LookupHostname(conn.RemoteAddr()), - replies: replies, - server: server, + channels: make(ChannelSet), + conn: conn, + hostname: LookupHostname(conn.RemoteAddr()), + replies: replies, + server: server, + serverPass: server.password == "", } go client.readConn(read) @@ -86,6 +88,9 @@ func (c *Client) Nick() string { } func (c *Client) UModeString() string { + if c.invisible { + return "i" + } return "" } diff --git a/irc/commands.go b/irc/commands.go index 53b529a7..cc85065a 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" "strings" + "unicode/utf8" ) type Command interface { @@ -371,14 +372,52 @@ func NewTopicCommand(args []string) (EditableCommand, error) { return msg, nil } +type Mode rune + +const ( + Away Mode = 'a' + Invisible Mode = 'i' + WallOps Mode = 'w' + Restricted Mode = 'r' + Operator Mode = 'o' + LocalOperator Mode = 'O' + ServerNotice Mode = 's' +) + +type ModeChange struct { + mode Mode + add bool // false => remove +} + +func (change *ModeChange) String() string { + sig := "+" + if !change.add { + sig = "-" + } + return fmt.Sprintf("%s%s", sig, change.mode) +} + type ModeCommand struct { BaseCommand nickname string - modes string + changes []ModeChange } func (cmd *ModeCommand) String() string { - return fmt.Sprintf("MODE(nickname=%s, modes=%s)", cmd.nickname, cmd.modes) + return fmt.Sprintf("MODE(nickname=%s, changes=%s)", cmd.nickname, cmd.changes) +} + +func stringToRunes(str string) <-chan rune { + runes := make(chan rune) + go func() { + for len(str) > 0 { + rune, size := utf8.DecodeRuneInString(str) + runes <- rune + str = str[size:] + } + close(runes) + }() + return runes } func NewModeCommand(args []string) (EditableCommand, error) { @@ -388,10 +427,26 @@ func NewModeCommand(args []string) (EditableCommand, error) { cmd := &ModeCommand{ nickname: args[0], + changes: make([]ModeChange, + utf8.RuneCountInString(strings.Join(args[1:], ""))-len(args[1:])), } - if len(args) > 1 { - cmd.modes = args[1] + index := 0 + for _, arg := range args[1:] { + modeChange := stringToRunes(arg) + sig := <-modeChange + if sig != '+' && sig != '-' { + return nil, ErrParseCommand + } + + add := sig == '+' + for mode := range modeChange { + cmd.changes[index] = ModeChange{ + mode: Mode(mode), + add: add, + } + index += 1 + } } return cmd, nil diff --git a/irc/server.go b/irc/server.go index 8e4cc604..379d4df6 100644 --- a/irc/server.go +++ b/irc/server.go @@ -266,5 +266,10 @@ func (m *PrivMsgCommand) HandleServer(s *Server) { } func (m *ModeCommand) HandleServer(s *Server) { + for _, change := range m.changes { + if change.mode == Invisible { + m.Client().invisible = change.add + } + } m.Client().replies <- RplUModeIs(s, m.Client()) }