diff --git a/irc/client.go b/irc/client.go index f42385a5..d563ad64 100644 --- a/irc/client.go +++ b/irc/client.go @@ -24,6 +24,7 @@ type Client struct { nick string channels []string + Support *iSupport conn net.Conn connected bool @@ -41,6 +42,7 @@ type Client struct { func NewClient(nick, username string) *Client { return &Client{ nick: nick, + Support: newISupport(), Username: username, Realname: nick, Messages: make(chan *Message, 32), diff --git a/irc/conn.go b/irc/conn.go index 2f8b12f3..4319deb5 100644 --- a/irc/conn.go +++ b/irc/conn.go @@ -222,6 +222,9 @@ func (c *Client) recv() { c.sendRecv.Add(1) go c.send() + case ReplyISupport: + c.Support.parse(msg.Params) + case ErrNicknameInUse: if c.HandleNickInUse != nil { go c.writeNick(c.HandleNickInUse(msg.Params[1])) diff --git a/irc/const.go b/irc/const.go index 660bc938..88c7306a 100644 --- a/irc/const.go +++ b/irc/const.go @@ -15,6 +15,7 @@ const ( ReplyWelcome = "001" ReplyYourHost = "002" ReplyCreated = "003" + ReplyISupport = "005" ReplyLUserClient = "251" ReplyLUserOp = "252" ReplyLUserUnknown = "253" diff --git a/irc/message.go b/irc/message.go index c2050c47..483be7e5 100644 --- a/irc/message.go +++ b/irc/message.go @@ -2,6 +2,9 @@ package irc import ( "strings" + "sync" + + "github.com/spf13/cast" ) type Message struct { @@ -65,3 +68,50 @@ func parseMessage(line string) *Message { return &msg } + +type iSupport struct { + support map[string]string + lock sync.Mutex +} + +func newISupport() *iSupport { + return &iSupport{ + support: map[string]string{}, + } +} + +func (i *iSupport) parse(params []string) { + for _, param := range params[1 : len(params)-1] { + parts := strings.SplitN(param, "=", 2) + i.lock.Lock() + if parts[0][0] == '-' { + delete(i.support, parts[0][1:]) + } else if len(parts) == 2 { + i.support[parts[0]] = parts[1] + } else { + i.support[param] = "" + } + i.lock.Unlock() + } +} + +func (i *iSupport) Has(key string) bool { + i.lock.Lock() + _, has := i.support[key] + i.lock.Unlock() + return has +} + +func (i *iSupport) Get(key string) string { + i.lock.Lock() + v := i.support[key] + i.lock.Unlock() + return v +} + +func (i *iSupport) GetInt(key string) int { + i.lock.Lock() + v := cast.ToInt(i.support[key]) + i.lock.Unlock() + return v +} diff --git a/irc/message_test.go b/irc/message_test.go index 1a172013..4556a2a0 100644 --- a/irc/message_test.go +++ b/irc/message_test.go @@ -119,3 +119,31 @@ func TestBadMessagePanic(t *testing.T) { parseMessage(":") parseMessage("") } + +func TestParseISupport(t *testing.T) { + s := newISupport() + s.parse([]string{"bob", "CAKE=31", "PIE", ":durr"}) + assert.Equal(t, 31, s.GetInt("CAKE")) + assert.Equal(t, "31", s.Get("CAKE")) + assert.True(t, s.Has("CAKE")) + assert.True(t, s.Has("PIE")) + assert.False(t, s.Has("APPLES")) + assert.Equal(t, "", s.Get("APPLES")) + assert.Equal(t, 0, s.GetInt("APPLES")) + + s.parse([]string{"bob", "-PIE", ":hurr"}) + assert.False(t, s.Has("PIE")) + + s.parse([]string{"bob", "CAKE=1337", ":durr"}) + assert.Equal(t, 1337, s.GetInt("CAKE")) + + s.parse([]string{"bob", "CAKE=", ":durr"}) + assert.Equal(t, "", s.Get("CAKE")) + assert.True(t, s.Has("CAKE")) + + s.parse([]string{"bob", "CAKE===", ":durr"}) + assert.Equal(t, "==", s.Get("CAKE")) + + s.parse([]string{"bob", "-CAKE=31", ":durr"}) + assert.False(t, s.Has("CAKE")) +}