source: code/trunk/vendor/gopkg.in/irc.v3/client_handlers.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 3.4 KB
RevLine 
[822]1package irc
2
3import (
4 "fmt"
5 "strings"
6)
7
8type clientFilter func(*Client, *Message)
9
10// clientFilters are pre-processing which happens for certain message
11// types. These were moved from below to keep the complexity of each
12// component down.
13var clientFilters = map[string]clientFilter{
14 "001": handle001,
15 "433": handle433,
16 "437": handle437,
17 "PING": handlePing,
18 "PONG": handlePong,
19 "NICK": handleNick,
20 "CAP": handleCap,
21}
22
23// From rfc2812 section 5.1 (Command responses)
24//
25// 001 RPL_WELCOME
26// "Welcome to the Internet Relay Network
27// <nick>!<user>@<host>"
28func handle001(c *Client, m *Message) {
29 c.currentNick = m.Params[0]
30 c.connected = true
31}
32
33// From rfc2812 section 5.2 (Error Replies)
34//
35// 433 ERR_NICKNAMEINUSE
36// "<nick> :Nickname is already in use"
37//
38// - Returned when a NICK message is processed that results
39// in an attempt to change to a currently existing
40// nickname.
41func handle433(c *Client, m *Message) {
42 // We only want to try and handle nick collisions during the initial
43 // handshake.
44 if c.connected {
45 return
46 }
47 c.currentNick += "_"
48 c.Writef("NICK :%s", c.currentNick)
49}
50
51// From rfc2812 section 5.2 (Error Replies)
52//
53// 437 ERR_UNAVAILRESOURCE
54// "<nick/channel> :Nick/channel is temporarily unavailable"
55//
56// - Returned by a server to a user trying to join a channel
57// currently blocked by the channel delay mechanism.
58//
59// - Returned by a server to a user trying to change nickname
60// when the desired nickname is blocked by the nick delay
61// mechanism.
62func handle437(c *Client, m *Message) {
63 // We only want to try and handle nick collisions during the initial
64 // handshake.
65 if c.connected {
66 return
67 }
68 c.currentNick += "_"
69 c.Writef("NICK :%s", c.currentNick)
70}
71
72func handlePing(c *Client, m *Message) {
73 reply := m.Copy()
74 reply.Command = "PONG"
75 c.WriteMessage(reply)
76}
77
78func handlePong(c *Client, m *Message) {
79 if c.incomingPongChan != nil {
80 select {
81 case c.incomingPongChan <- m.Trailing():
82 default:
83 // Note that this return isn't really needed, but it helps some code
84 // coverage tools actually see this line.
85 return
86 }
87 }
88}
89
90func handleNick(c *Client, m *Message) {
91 if m.Prefix.Name == c.currentNick && len(m.Params) > 0 {
92 c.currentNick = m.Params[0]
93 }
94}
95
96var capFilters = map[string]clientFilter{
97 "LS": handleCapLs,
98 "ACK": handleCapAck,
99 "NAK": handleCapNak,
100}
101
102func handleCap(c *Client, m *Message) {
103 if c.remainingCapResponses <= 0 || len(m.Params) <= 2 {
104 return
105 }
106
107 if filter, ok := capFilters[m.Params[1]]; ok {
108 filter(c, m)
109 }
110
111 if c.remainingCapResponses <= 0 {
112 for key, cap := range c.caps {
113 if cap.Required && !cap.Enabled {
114 c.sendError(fmt.Errorf("CAP %s requested but not accepted", key))
115 return
116 }
117 }
118
119 c.Write("CAP END")
120 }
121}
122
123func handleCapLs(c *Client, m *Message) {
124 for _, key := range strings.Split(m.Trailing(), " ") {
125 cap := c.caps[key]
126 cap.Available = true
127 c.caps[key] = cap
128 }
129 c.remainingCapResponses--
130}
131
132func handleCapAck(c *Client, m *Message) {
133 for _, key := range strings.Split(m.Trailing(), " ") {
134 cap := c.caps[key]
135 cap.Enabled = true
136 c.caps[key] = cap
137 }
138 c.remainingCapResponses--
139}
140
141func handleCapNak(c *Client, m *Message) {
142 // If we got a NAK and this REQ was required, we need to bail
143 // with an error.
144 for _, key := range strings.Split(m.Trailing(), " ") {
145 if c.caps[key].Required {
146 c.sendError(fmt.Errorf("CAP %s requested but was rejected", key))
147 return
148 }
149 }
150 c.remainingCapResponses--
151}
Note: See TracBrowser for help on using the repository browser.