diff options
author | Hubert Hirtz <hubert@hirtzfr.eu> | 2020-08-17 20:21:03 +0200 |
---|---|---|
committer | Hubert Hirtz <hubert@hirtzfr.eu> | 2020-08-17 20:21:03 +0200 |
commit | 190343edf7a6540352a03a4b0cde46ad6d538a01 (patch) | |
tree | 01f511b6343416824139c9488799a69eb1a056fa /irc | |
parent | irc: Handle CAP NEW/DEL/NAK before registration (diff) |
Add /names command
Diffstat (limited to 'irc')
-rw-r--r-- | irc/states.go | 117 | ||||
-rw-r--r-- | irc/tokens.go | 2 |
2 files changed, 77 insertions, 42 deletions
diff --git a/irc/states.go b/irc/states.go index 31d8929..b09a562 100644 --- a/irc/states.go +++ b/irc/states.go @@ -111,17 +111,13 @@ type User struct { type Channel struct { Name string - Members map[string]string + Members map[*User]string Topic string TopicWho string TopicTime time.Time Secret bool } -func (c *Channel) SetTopic(topic string) { - c.Topic = topic -} - type SessionParams struct { Nickname string Username string @@ -156,7 +152,7 @@ type Session struct { enabledCaps map[string]struct{} features map[string]string - users map[string]User + users map[string]*User channels map[string]Channel chBatches map[string]HistoryEvent } @@ -177,7 +173,7 @@ func NewSession(conn io.ReadWriteCloser, params SessionParams) (s Session, err e availableCaps: map[string]string{}, enabledCaps: map[string]struct{}{}, features: map[string]string{}, - users: map[string]User{}, + users: map[string]*User{}, channels: map[string]Channel{}, chBatches: map[string]HistoryEvent{}, } @@ -243,6 +239,20 @@ func (s *Session) IsChannel(name string) bool { return strings.IndexAny(name, "#&") == 0 // TODO compute CHANTYPES } +func (s *Session) Names(channel string) []Name { + var names []Name + if c, ok := s.channels[strings.ToLower(channel)]; ok { + names = make([]Name, 0, len(c.Members)) + for u, pl := range c.Members { + names = append(names, Name{ + PowerLevel: pl, + Nick: u.Nick, + }) + } + } + return names +} + func (s *Session) Topic(channel string) (topic string, who string, at time.Time) { channelCf := strings.ToLower(channel) if c, ok := s.channels[channelCf]; ok { @@ -505,6 +515,7 @@ func (s *Session) handle(msg Message) (err error) { s.nick = msg.Params[0] s.nickCf = strings.ToLower(s.nick) s.registered = true + s.users[s.nickCf] = &User{Nick: s.nick} s.evts <- RegisteredEvent{} if s.host == "" { @@ -604,13 +615,13 @@ func (s *Session) handle(msg Message) (err error) { if nickCf == s.nickCf { s.channels[channelCf] = Channel{ Name: msg.Params[0], - Members: map[string]string{}, + Members: map[*User]string{}, } } else if c, ok := s.channels[channelCf]; ok { if _, ok := s.users[nickCf]; !ok { - s.users[nickCf] = User{Nick: nick} + s.users[nickCf] = &User{Nick: nick} } - c.Members[nickCf] = "" + c.Members[s.users[nickCf]] = "" t, ok := msg.Time() if !ok { @@ -629,61 +640,72 @@ func (s *Session) handle(msg Message) (err error) { channelCf := strings.ToLower(msg.Params[0]) if nickCf == s.nickCf { - delete(s.channels, channelCf) - s.evts <- SelfPartEvent{Channel: msg.Params[0]} + if c, ok := s.channels[channelCf]; ok { + delete(s.channels, channelCf) + for u := range c.Members { + s.cleanUser(u) + } + s.evts <- SelfPartEvent{Channel: msg.Params[0]} + } } else if c, ok := s.channels[channelCf]; ok { - delete(c.Members, nickCf) + if u, ok := s.users[nickCf]; ok { + delete(c.Members, u) + s.cleanUser(u) - t, ok := msg.Time() - if !ok { - t = time.Now() - } + t, ok := msg.Time() + if !ok { + t = time.Now() + } - s.evts <- UserPartEvent{ - Channels: []string{c.Name}, - Nick: nick, - Time: t, + s.evts <- UserPartEvent{ + Channels: []string{c.Name}, + Nick: nick, + Time: t, + } } } case "QUIT": nick, _, _ := FullMask(msg.Prefix) nickCf := strings.ToLower(nick) - t, ok := msg.Time() - if !ok { - t = time.Now() - } - - var channels []string + if u, ok := s.users[nickCf]; ok { + t, ok := msg.Time() + if !ok { + t = time.Now() + } - for _, c := range s.channels { - if _, ok := c.Members[nickCf]; !ok { - continue + var channels []string + for _, c := range s.channels { + if _, ok := c.Members[u]; ok { + channels = append(channels, c.Name) + delete(c.Members, u) + s.cleanUser(u) + } } - channels = append(channels, c.Name) - } - s.evts <- UserPartEvent{ - Channels: channels, - Nick: nick, - Time: t, + s.evts <- UserPartEvent{ + Channels: channels, + Nick: nick, + Time: t, + } } case rplNamreply: channelCf := strings.ToLower(msg.Params[2]) if c, ok := s.channels[channelCf]; ok { c.Secret = msg.Params[1] == "@" - names := TokenizeNames(msg.Params[3], "~&@%+") // TODO compute prefixes - for _, name := range names { + for _, name := range TokenizeNames(msg.Params[3], "~&@%+") { nick := name.Nick nickCf := strings.ToLower(nick) if _, ok := s.users[nickCf]; !ok { - s.users[nickCf] = User{Nick: nick} + s.users[nickCf] = &User{Nick: nick} } - c.Members[nickCf] = name.PowerLevel + c.Members[s.users[nickCf]] = name.PowerLevel } + + s.channels[channelCf] = c } case rplEndofnames: channelCf := strings.ToLower(msg.Params[1]) @@ -782,6 +804,11 @@ func (s *Session) handle(msg Message) (err error) { t = time.Now() } + formerUser := s.users[nickCf] + formerUser.Nick = newNick + delete(s.users, nickCf) + s.users[newNickCf] = formerUser + if nickCf == s.nickCf { s.evts <- SelfNickEvent{ FormerNick: s.nick, @@ -796,7 +823,6 @@ func (s *Session) handle(msg Message) (err error) { NewNick: newNick, Time: t, } - // TODO update state } case "FAIL": fmt.Println("FAIL", msg.Params) @@ -848,6 +874,15 @@ func (s *Session) privmsgToEvent(msg Message) (ev Event) { return } +func (s *Session) cleanUser(parted *User) { + for _, c := range s.channels { + if _, ok := c.Members[parted]; ok { + return + } + } + delete(s.users, strings.ToLower(parted.Nick)) +} + func (s *Session) updateFeatures(features []string) { for _, f := range features { if f == "" || f == "-" || f == "=" || f == "-=" { diff --git a/irc/tokens.go b/irc/tokens.go index 5c156b3..179454c 100644 --- a/irc/tokens.go +++ b/irc/tokens.go @@ -244,7 +244,7 @@ func (msg *Message) IsValid() bool { return 4 <= len(msg.Params) case rplWhoreply: return 8 <= len(msg.Params) - case "JOIN", "PART", "TAGMSG": + case "JOIN", "NICK", "PART", "TAGMSG": return 1 <= len(msg.Params) && msg.Prefix != "" case "PRIVMSG", "NOTICE", "TOPIC": return 2 <= len(msg.Params) && msg.Prefix != "" |