commit 190343e

Hubert Hirtz  ·  2020-08-17 18:21:03 +0000 UTC
parent ba679ce
Add /names command
3 files changed,  +95, -42
M app.go
M app.go
+18, -0
 1@@ -320,6 +320,24 @@ func (app *App) handleInput(buffer, content string) {
 2 		}
 3 
 4 		app.s.Part(args)
 5+	case "NAMES":
 6+		if buffer == ui.Home {
 7+			return
 8+		}
 9+
10+		var sb strings.Builder
11+		sb.WriteString("\x0314Names: ")
12+		for _, name := range app.s.Names(buffer) {
13+			if name.PowerLevel != "" {
14+				sb.WriteString("\x033")
15+				sb.WriteString(name.PowerLevel)
16+				sb.WriteString("\x0314")
17+			}
18+			sb.WriteString(name.Nick)
19+			sb.WriteRune(' ')
20+		}
21+		line := sb.String()
22+		app.win.AddLine(buffer, ui.NewLineNow("--", line[:len(line)-1]))
23 	case "TOPIC":
24 		if buffer == ui.Home {
25 			return
+76, -41
  1@@ -111,17 +111,13 @@ type User struct {
  2 
  3 type Channel struct {
  4 	Name      string
  5-	Members   map[string]string
  6+	Members   map[*User]string
  7 	Topic     string
  8 	TopicWho  string
  9 	TopicTime time.Time
 10 	Secret    bool
 11 }
 12 
 13-func (c *Channel) SetTopic(topic string) {
 14-	c.Topic = topic
 15-}
 16-
 17 type SessionParams struct {
 18 	Nickname string
 19 	Username string
 20@@ -156,7 +152,7 @@ type Session struct {
 21 	enabledCaps   map[string]struct{}
 22 	features      map[string]string
 23 
 24-	users     map[string]User
 25+	users     map[string]*User
 26 	channels  map[string]Channel
 27 	chBatches map[string]HistoryEvent
 28 }
 29@@ -177,7 +173,7 @@ func NewSession(conn io.ReadWriteCloser, params SessionParams) (s Session, err e
 30 		availableCaps: map[string]string{},
 31 		enabledCaps:   map[string]struct{}{},
 32 		features:      map[string]string{},
 33-		users:         map[string]User{},
 34+		users:         map[string]*User{},
 35 		channels:      map[string]Channel{},
 36 		chBatches:     map[string]HistoryEvent{},
 37 	}
 38@@ -243,6 +239,20 @@ func (s *Session) IsChannel(name string) bool {
 39 	return strings.IndexAny(name, "#&") == 0 // TODO compute CHANTYPES
 40 }
 41 
 42+func (s *Session) Names(channel string) []Name {
 43+	var names []Name
 44+	if c, ok := s.channels[strings.ToLower(channel)]; ok {
 45+		names = make([]Name, 0, len(c.Members))
 46+		for u, pl := range c.Members {
 47+			names = append(names, Name{
 48+				PowerLevel: pl,
 49+				Nick:       u.Nick,
 50+			})
 51+		}
 52+	}
 53+	return names
 54+}
 55+
 56 func (s *Session) Topic(channel string) (topic string, who string, at time.Time) {
 57 	channelCf := strings.ToLower(channel)
 58 	if c, ok := s.channels[channelCf]; ok {
 59@@ -505,6 +515,7 @@ func (s *Session) handle(msg Message) (err error) {
 60 		s.nick = msg.Params[0]
 61 		s.nickCf = strings.ToLower(s.nick)
 62 		s.registered = true
 63+		s.users[s.nickCf] = &User{Nick: s.nick}
 64 		s.evts <- RegisteredEvent{}
 65 
 66 		if s.host == "" {
 67@@ -604,13 +615,13 @@ func (s *Session) handle(msg Message) (err error) {
 68 		if nickCf == s.nickCf {
 69 			s.channels[channelCf] = Channel{
 70 				Name:    msg.Params[0],
 71-				Members: map[string]string{},
 72+				Members: map[*User]string{},
 73 			}
 74 		} else if c, ok := s.channels[channelCf]; ok {
 75 			if _, ok := s.users[nickCf]; !ok {
 76-				s.users[nickCf] = User{Nick: nick}
 77+				s.users[nickCf] = &User{Nick: nick}
 78 			}
 79-			c.Members[nickCf] = ""
 80+			c.Members[s.users[nickCf]] = ""
 81 
 82 			t, ok := msg.Time()
 83 			if !ok {
 84@@ -629,61 +640,72 @@ func (s *Session) handle(msg Message) (err error) {
 85 		channelCf := strings.ToLower(msg.Params[0])
 86 
 87 		if nickCf == s.nickCf {
 88-			delete(s.channels, channelCf)
 89-			s.evts <- SelfPartEvent{Channel: msg.Params[0]}
 90+			if c, ok := s.channels[channelCf]; ok {
 91+				delete(s.channels, channelCf)
 92+				for u := range c.Members {
 93+					s.cleanUser(u)
 94+				}
 95+				s.evts <- SelfPartEvent{Channel: msg.Params[0]}
 96+			}
 97 		} else if c, ok := s.channels[channelCf]; ok {
 98-			delete(c.Members, nickCf)
 99+			if u, ok := s.users[nickCf]; ok {
100+				delete(c.Members, u)
101+				s.cleanUser(u)
102 
103-			t, ok := msg.Time()
104-			if !ok {
105-				t = time.Now()
106-			}
107+				t, ok := msg.Time()
108+				if !ok {
109+					t = time.Now()
110+				}
111 
112-			s.evts <- UserPartEvent{
113-				Channels: []string{c.Name},
114-				Nick:     nick,
115-				Time:     t,
116+				s.evts <- UserPartEvent{
117+					Channels: []string{c.Name},
118+					Nick:     nick,
119+					Time:     t,
120+				}
121 			}
122 		}
123 	case "QUIT":
124 		nick, _, _ := FullMask(msg.Prefix)
125 		nickCf := strings.ToLower(nick)
126 
127-		t, ok := msg.Time()
128-		if !ok {
129-			t = time.Now()
130-		}
131-
132-		var channels []string
133+		if u, ok := s.users[nickCf]; ok {
134+			t, ok := msg.Time()
135+			if !ok {
136+				t = time.Now()
137+			}
138 
139-		for _, c := range s.channels {
140-			if _, ok := c.Members[nickCf]; !ok {
141-				continue
142+			var channels []string
143+			for _, c := range s.channels {
144+				if _, ok := c.Members[u]; ok {
145+					channels = append(channels, c.Name)
146+					delete(c.Members, u)
147+					s.cleanUser(u)
148+				}
149 			}
150-			channels = append(channels, c.Name)
151-		}
152 
153-		s.evts <- UserPartEvent{
154-			Channels: channels,
155-			Nick:     nick,
156-			Time:     t,
157+			s.evts <- UserPartEvent{
158+				Channels: channels,
159+				Nick:     nick,
160+				Time:     t,
161+			}
162 		}
163 	case rplNamreply:
164 		channelCf := strings.ToLower(msg.Params[2])
165 
166 		if c, ok := s.channels[channelCf]; ok {
167 			c.Secret = msg.Params[1] == "@"
168-			names := TokenizeNames(msg.Params[3], "~&@%+") // TODO compute prefixes
169 
170-			for _, name := range names {
171+			for _, name := range TokenizeNames(msg.Params[3], "~&@%+") {
172 				nick := name.Nick
173 				nickCf := strings.ToLower(nick)
174 
175 				if _, ok := s.users[nickCf]; !ok {
176-					s.users[nickCf] = User{Nick: nick}
177+					s.users[nickCf] = &User{Nick: nick}
178 				}
179-				c.Members[nickCf] = name.PowerLevel
180+				c.Members[s.users[nickCf]] = name.PowerLevel
181 			}
182+
183+			s.channels[channelCf] = c
184 		}
185 	case rplEndofnames:
186 		channelCf := strings.ToLower(msg.Params[1])
187@@ -782,6 +804,11 @@ func (s *Session) handle(msg Message) (err error) {
188 			t = time.Now()
189 		}
190 
191+		formerUser := s.users[nickCf]
192+		formerUser.Nick = newNick
193+		delete(s.users, nickCf)
194+		s.users[newNickCf] = formerUser
195+
196 		if nickCf == s.nickCf {
197 			s.evts <- SelfNickEvent{
198 				FormerNick: s.nick,
199@@ -796,7 +823,6 @@ func (s *Session) handle(msg Message) (err error) {
200 				NewNick:    newNick,
201 				Time:       t,
202 			}
203-			// TODO update state
204 		}
205 	case "FAIL":
206 		fmt.Println("FAIL", msg.Params)
207@@ -848,6 +874,15 @@ func (s *Session) privmsgToEvent(msg Message) (ev Event) {
208 	return
209 }
210 
211+func (s *Session) cleanUser(parted *User) {
212+	for _, c := range s.channels {
213+		if _, ok := c.Members[parted]; ok {
214+			return
215+		}
216+	}
217+	delete(s.users, strings.ToLower(parted.Nick))
218+}
219+
220 func (s *Session) updateFeatures(features []string) {
221 	for _, f := range features {
222 		if f == "" || f == "-" || f == "=" || f == "-=" {
+1, -1
1@@ -244,7 +244,7 @@ func (msg *Message) IsValid() bool {
2 		return 4 <= len(msg.Params)
3 	case rplWhoreply:
4 		return 8 <= len(msg.Params)
5-	case "JOIN", "PART", "TAGMSG":
6+	case "JOIN", "NICK", "PART", "TAGMSG":
7 		return 1 <= len(msg.Params) && msg.Prefix != ""
8 	case "PRIVMSG", "NOTICE", "TOPIC":
9 		return 2 <= len(msg.Params) && msg.Prefix != ""