diff --git a/pkg/irc/client.go b/pkg/irc/client.go index e9ac9e51..b20ddd0d 100644 --- a/pkg/irc/client.go +++ b/pkg/irc/client.go @@ -30,7 +30,7 @@ type Config struct { } type Client struct { - Config Config + Config *Config Messages chan *Message ConnectionChanged chan ConnectionState @@ -57,7 +57,7 @@ type Client struct { lock sync.Mutex } -func NewClient(config Config) *Client { +func NewClient(config *Config) *Client { if config.Port == "" { if config.TLS { config.Port = "6697" @@ -74,11 +74,18 @@ func NewClient(config Config) *Client { config.Realname = config.Nick } - c := Client{ + wantedCapabilities := append([]string{}, clientWantedCaps...) + + if config.SASL != nil { + wantedCapabilities = append(wantedCapabilities, "sasl") + } + + return &Client{ Config: config, nick: config.Nick, Features: NewFeatures(), Messages: make(chan *Message, 32), + wantedCapabilities: wantedCapabilities, requestedCapabilities: map[string][]string{}, enabledCapabilities: map[string][]string{}, ConnectionChanged: make(chan ConnectionState, 4), @@ -93,14 +100,6 @@ func NewClient(config Config) *Client { Jitter: true, }, } - - c.wantedCapabilities = append(c.wantedCapabilities, clientWantedCaps...) - - if config.SASL != nil { - c.wantedCapabilities = append(c.wantedCapabilities, "sasl") - } - - return &c } func (c *Client) GetNick() string { diff --git a/pkg/irc/client_test.go b/pkg/irc/client_test.go index a847773f..bcae9925 100644 --- a/pkg/irc/client_test.go +++ b/pkg/irc/client_test.go @@ -8,7 +8,7 @@ import ( ) func testClientSend() (*Client, chan string) { - c := NewClient(Config{}) + c := NewClient(&Config{}) conn := &mockConn{hook: make(chan string, 16)} c.conn = conn c.sendRecv.Add(1) @@ -147,7 +147,6 @@ func TestRegister(t *testing.T) { c.Config.Nick = "nick" c.Config.Username = "user" c.Config.Realname = "rn" - t.Log(c.Config) c.register() assert.Equal(t, "CAP LS 302\r\n", <-out) assert.Equal(t, "NICK nick\r\n", <-out) diff --git a/pkg/irc/conn.go b/pkg/irc/conn.go index 3a32f2c9..e96a3069 100644 --- a/pkg/irc/conn.go +++ b/pkg/irc/conn.go @@ -200,12 +200,12 @@ func (c *Client) recv() { go c.write("PONG :" + msg.LastParam()) case JOIN: - if c.EqualFold(msg.Nick, c.GetNick()) { + if c.Is(msg.Sender) { c.addChannel(msg.Params[0]) } case NICK: - if c.EqualFold(msg.Nick, c.GetNick()) { + if c.Is(msg.Sender) { c.setNick(msg.LastParam()) } diff --git a/pkg/irc/conn_test.go b/pkg/irc/conn_test.go index 62d52335..f8297f2d 100644 --- a/pkg/irc/conn_test.go +++ b/pkg/irc/conn_test.go @@ -78,7 +78,7 @@ func (i *mockIrcd) handle(conn net.Conn) { } func TestConnect(t *testing.T) { - c := NewClient(Config{ + c := NewClient(&Config{ Host: "127.0.0.1", Port: "45678", }) @@ -87,7 +87,7 @@ func TestConnect(t *testing.T) { } func TestConnectTLS(t *testing.T) { - c := NewClient(Config{ + c := NewClient(&Config{ Host: "127.0.0.1", Port: "45679", TLS: true, @@ -100,12 +100,12 @@ func TestConnectTLS(t *testing.T) { } func TestConnectDefaultPorts(t *testing.T) { - c := NewClient(Config{ + c := NewClient(&Config{ Host: "127.0.0.1", }) assert.Equal(t, "6667", c.Config.Port) - c = NewClient(Config{ + c = NewClient(&Config{ Host: "127.0.0.1", TLS: true, }) @@ -125,7 +125,7 @@ func TestWrite(t *testing.T) { } func TestRecv(t *testing.T) { - c := NewClient(Config{}) + c := NewClient(&Config{}) conn := &mockConn{hook: make(chan string, 16)} c.conn = conn @@ -145,7 +145,7 @@ func TestRecv(t *testing.T) { } func TestRecvTriggersReconnect(t *testing.T) { - c := NewClient(Config{}) + c := NewClient(&Config{}) c.conn = &mockConn{} c.scan = bufio.NewScanner(bytes.NewBufferString("001 bob\r\n")) done := make(chan struct{}) @@ -168,7 +168,7 @@ func TestRecvTriggersReconnect(t *testing.T) { } func TestClose(t *testing.T) { - c := NewClient(Config{}) + c := NewClient(&Config{}) close(c.quit) ok := false done := make(chan struct{}) diff --git a/pkg/irc/ctcp.go b/pkg/irc/ctcp.go index 3c3df808..7f82676e 100644 --- a/pkg/irc/ctcp.go +++ b/pkg/irc/ctcp.go @@ -45,25 +45,25 @@ func EncodeCTCP(ctcp *CTCP) string { func (c *Client) handleCTCP(ctcp *CTCP, msg *Message) { switch ctcp.Command { case "CLIENTINFO": - c.ReplyCTCP(msg.Nick, ctcp.Command, ClientInfo) + c.ReplyCTCP(msg.Sender, ctcp.Command, ClientInfo) case "FINGER", "VERSION": if c.Config.Version != "" { - c.ReplyCTCP(msg.Nick, ctcp.Command, c.Config.Version) + c.ReplyCTCP(msg.Sender, ctcp.Command, c.Config.Version) } case "PING": - c.ReplyCTCP(msg.Nick, ctcp.Command, ctcp.Params) + c.ReplyCTCP(msg.Sender, ctcp.Command, ctcp.Params) case "SOURCE": if c.Config.Source != "" { - c.ReplyCTCP(msg.Nick, ctcp.Command, c.Config.Source) + c.ReplyCTCP(msg.Sender, ctcp.Command, c.Config.Source) } case "TIME": - c.ReplyCTCP(msg.Nick, ctcp.Command, time.Now().UTC().Format(time.RFC3339)) + c.ReplyCTCP(msg.Sender, ctcp.Command, time.Now().UTC().Format(time.RFC3339)) case "USERINFO": - c.ReplyCTCP(msg.Nick, ctcp.Command, fmt.Sprintf("%s (%s)", c.GetNick(), c.Config.Realname)) + c.ReplyCTCP(msg.Sender, ctcp.Command, fmt.Sprintf("%s (%s)", c.GetNick(), c.Config.Realname)) } } diff --git a/pkg/irc/message.go b/pkg/irc/message.go index ed67e54c..af05b9bc 100644 --- a/pkg/irc/message.go +++ b/pkg/irc/message.go @@ -6,8 +6,9 @@ import ( type Message struct { Tags map[string]string - Prefix string - Nick string + Sender string + Ident string + Host string Command string Params []string } @@ -20,7 +21,7 @@ func (m *Message) LastParam() string { } func (m *Message) IsFromServer() bool { - return m.Nick == "" || strings.Contains(m.Nick, ".") + return m.Sender == "" || strings.Contains(m.Sender, ".") } func (m *Message) ToCTCP() *CTCP { @@ -65,14 +66,23 @@ func ParseMessage(line string) *Message { if next == -1 { return nil } - msg.Prefix = line[1:next] + prefix := line[1:next] - if i := strings.Index(msg.Prefix, "!"); i > 0 { - msg.Nick = msg.Prefix[:i] - } else if i := strings.Index(msg.Prefix, "@"); i > 0 { - msg.Nick = msg.Prefix[:i] + if i := strings.Index(prefix, "!"); i > 0 { + msg.Sender = prefix[:i] + prefix = prefix[i+1:] + + if i = strings.Index(prefix, "@"); i > 0 { + msg.Ident = prefix[:i] + msg.Host = prefix[i+1:] + } else { + msg.Ident = prefix + } + } else if i = strings.Index(prefix, "@"); i > 0 { + msg.Sender = prefix[:i] + msg.Host = prefix[i+1:] } else { - msg.Nick = msg.Prefix + msg.Sender = prefix } line = line[next+1:] diff --git a/pkg/irc/message_test.go b/pkg/irc/message_test.go index f4ddc27e..63e81a52 100644 --- a/pkg/irc/message_test.go +++ b/pkg/irc/message_test.go @@ -14,16 +14,16 @@ func TestParseMessage(t *testing.T) { { ":user CMD #chan :some message", &Message{ - Prefix: "user", - Nick: "user", + Sender: "user", Command: "CMD", Params: []string{"#chan", "some message"}, }, }, { ":nick!user@host.com CMD a b", &Message{ - Prefix: "nick!user@host.com", - Nick: "nick", + Sender: "nick", + Ident: "user", + Host: "host.com", Command: "CMD", Params: []string{"a", "b"}, }, @@ -53,15 +53,16 @@ func TestParseMessage(t *testing.T) { }, { ":nick@host.com CMD", &Message{ - Prefix: "nick@host.com", - Nick: "nick", + Sender: "nick", + Host: "host.com", Command: "CMD", }, }, { ":ni@ck!user!name@host!.com CMD", &Message{ - Prefix: "ni@ck!user!name@host!.com", - Nick: "ni@ck", + Sender: "ni@ck", + Ident: "user!name", + Host: "host!.com", Command: "CMD", }, }, { @@ -114,18 +115,20 @@ func TestParseMessage(t *testing.T) { Tags: map[string]string{ "x": "y", }, - Prefix: "nick!user@host.com", - Nick: "nick", + Sender: "nick", + Ident: "user", + Host: "host.com", Command: "CMD", }, }, { - "@x=y :nick!user@host.com CMD :pie and cake", + "@x=y :nick!user@host.com CMD :pie and cake", &Message{ Tags: map[string]string{ "x": "y", }, - Prefix: "nick!user@host.com", - Nick: "nick", + Sender: "nick", + Ident: "user", + Host: "host.com", Command: "CMD", Params: []string{"pie and cake"}, }, @@ -135,8 +138,9 @@ func TestParseMessage(t *testing.T) { Tags: map[string]string{ "x": "y", }, - Prefix: "nick!user@host.com", - Nick: "nick", + Sender: "nick", + Ident: "user", + Host: "host.com", Command: "CMD", Params: []string{"beans", "rainbows", "pie and cake"}, }, diff --git a/server/irc.go b/server/irc.go index a7fbf2cd..9b755bb4 100644 --- a/server/irc.go +++ b/server/irc.go @@ -72,7 +72,7 @@ func connectIRC(server *storage.Server, state *State, srcIP []byte) *irc.Client ircCfg.Password = server.ServerPassword } - i := irc.NewClient(ircCfg) + i := irc.NewClient(&ircCfg) i.Config.HandleNickInUse = createNickInUseHandler(i, state) state.setIRC(server.Host, i) diff --git a/server/irc_handler.go b/server/irc_handler.go index cf9b49fc..5d402d48 100644 --- a/server/irc_handler.go +++ b/server/irc_handler.go @@ -113,11 +113,11 @@ func (i *ircHandler) dispatchMessage(msg *irc.Message) { func (i *ircHandler) nick(msg *irc.Message) { i.state.sendJSON("nick", Nick{ Server: i.client.Host(), - Old: msg.Nick, + Old: msg.Sender, New: msg.LastParam(), }) - channelStore.RenameUser(msg.Nick, msg.LastParam(), i.client.Host()) + channelStore.RenameUser(msg.Sender, msg.LastParam(), i.client.Host()) if i.client.Is(msg.LastParam()) { go i.state.user.SetNick(msg.LastParam(), i.client.Host()) @@ -127,14 +127,14 @@ func (i *ircHandler) nick(msg *irc.Message) { func (i *ircHandler) join(msg *irc.Message) { i.state.sendJSON("join", Join{ Server: i.client.Host(), - User: msg.Nick, + User: msg.Sender, Channels: msg.Params, }) channel := msg.Params[0] - channelStore.AddUser(msg.Nick, i.client.Host(), channel) + channelStore.AddUser(msg.Sender, i.client.Host(), channel) - if i.client.Is(msg.Nick) { + if i.client.Is(msg.Sender) { // In case no topic is set and there's a cached one that needs to be cleared i.client.Topic(channel) @@ -150,7 +150,7 @@ func (i *ircHandler) join(msg *irc.Message) { func (i *ircHandler) part(msg *irc.Message) { part := Part{ Server: i.client.Host(), - User: msg.Nick, + User: msg.Sender, Channel: msg.Params[0], } @@ -160,9 +160,9 @@ func (i *ircHandler) part(msg *irc.Message) { i.state.sendJSON("part", part) - channelStore.RemoveUser(msg.Nick, i.client.Host(), part.Channel) + channelStore.RemoveUser(msg.Sender, i.client.Host(), part.Channel) - if i.client.Is(msg.Nick) { + if i.client.Is(msg.Sender) { go i.state.user.RemoveChannel(i.client.Host(), part.Channel) } } @@ -196,7 +196,7 @@ func (i *ircHandler) message(msg *irc.Message) { message := Message{ ID: betterguid.New(), Server: i.client.Host(), - From: msg.Nick, + From: msg.Sender, Content: msg.LastParam(), } target := msg.Params[0] @@ -216,18 +216,18 @@ func (i *ircHandler) message(msg *irc.Message) { if target != "*" && !msg.IsFromServer() { go i.state.user.LogMessage(message.ID, - i.client.Host(), msg.Nick, target, msg.LastParam()) + i.client.Host(), msg.Sender, target, msg.LastParam()) } } func (i *ircHandler) quit(msg *irc.Message) { i.state.sendJSON("quit", Quit{ Server: i.client.Host(), - User: msg.Nick, + User: msg.Sender, Reason: msg.LastParam(), }) - channelStore.RemoveUserAll(msg.Nick, i.client.Host()) + channelStore.RemoveUserAll(msg.Sender, i.client.Host()) } func (i *ircHandler) info(msg *irc.Message) { @@ -248,7 +248,7 @@ func (i *ircHandler) info(msg *irc.Message) { i.state.sendJSON("pm", Message{ Server: i.client.Host(), - From: msg.Nick, + From: msg.Sender, Content: strings.Join(msg.Params[1:], " "), }) } @@ -297,7 +297,7 @@ func (i *ircHandler) topic(msg *irc.Message) { if msg.Command == irc.TOPIC { channel = msg.Params[0] - nick = msg.Nick + nick = msg.Sender } else { channel = msg.Params[1] } @@ -425,7 +425,7 @@ func (i *ircHandler) receiveDCCSend(pack *irc.DCCSend, msg *irc.Message) { i.state.sendJSON("dcc_send", DCCSend{ Server: i.client.Host(), - From: msg.Nick, + From: msg.Sender, Filename: pack.File, URL: fmt.Sprintf("%s://%s/downloads/%s/%s", i.state.String("scheme"), i.state.String("host"), i.state.user.Username, pack.File), @@ -539,5 +539,5 @@ func formatIRCError(msg *irc.Message) string { } func printMessage(msg *irc.Message, i *irc.Client) { - log.Println(i.GetNick()+":", msg.Prefix, msg.Command, msg.Params) + log.Println(i.GetNick()+":", msg.Sender, msg.Command, msg.Params) } diff --git a/server/irc_handler_test.go b/server/irc_handler_test.go index 9dc55f40..2ea3a3ee 100644 --- a/server/irc_handler_test.go +++ b/server/irc_handler_test.go @@ -54,7 +54,7 @@ func dispatchMessage(msg *irc.Message) WSResponse { } func dispatchMessageMulti(msg *irc.Message) chan WSResponse { - c := irc.NewClient(irc.Config{ + c := irc.NewClient(&irc.Config{ Nick: "nick", Username: "user", Host: "host.com", @@ -74,7 +74,7 @@ func checkResponse(t *testing.T, expectedType string, expectedData interface{}, func TestHandleIRCNick(t *testing.T) { res := dispatchMessage(&irc.Message{ Command: irc.NICK, - Nick: "old", + Sender: "old", Params: []string{"new"}, }) @@ -88,7 +88,7 @@ func TestHandleIRCNick(t *testing.T) { func TestHandleIRCJoin(t *testing.T) { res := dispatchMessage(&irc.Message{ Command: irc.JOIN, - Nick: "joining", + Sender: "joining", Params: []string{"#chan"}, }) @@ -102,7 +102,7 @@ func TestHandleIRCJoin(t *testing.T) { func TestHandleIRCPart(t *testing.T) { res := dispatchMessage(&irc.Message{ Command: irc.PART, - Nick: "parting", + Sender: "parting", Params: []string{"#chan", "the reason"}, }) @@ -115,7 +115,7 @@ func TestHandleIRCPart(t *testing.T) { res = dispatchMessage(&irc.Message{ Command: irc.PART, - Nick: "parting", + Sender: "parting", Params: []string{"#chan"}, }) @@ -144,7 +144,7 @@ func TestHandleIRCMode(t *testing.T) { func TestHandleIRCMessage(t *testing.T) { res := dispatchMessage(&irc.Message{ Command: irc.PRIVMSG, - Nick: "nick", + Sender: "nick", Params: []string{"#chan", "the message"}, }) @@ -157,7 +157,7 @@ func TestHandleIRCMessage(t *testing.T) { res = dispatchMessage(&irc.Message{ Command: irc.PRIVMSG, - Nick: "someone", + Sender: "someone", Params: []string{"nick", "the message"}, }) @@ -172,7 +172,7 @@ func TestHandleIRCMessage(t *testing.T) { func TestHandleIRCQuit(t *testing.T) { res := dispatchMessage(&irc.Message{ Command: irc.QUIT, - Nick: "nick", + Sender: "nick", Params: []string{"the reason"}, }) @@ -186,7 +186,7 @@ func TestHandleIRCQuit(t *testing.T) { func TestHandleIRCWelcome(t *testing.T) { res := dispatchMessageMulti(&irc.Message{ Command: irc.RPL_WELCOME, - Nick: "nick", + Sender: "nick", Params: []string{"nick", "some", "text"}, }) @@ -203,7 +203,7 @@ func TestHandleIRCWelcome(t *testing.T) { } func TestHandleIRCWhois(t *testing.T) { - c := irc.NewClient(irc.Config{ + c := irc.NewClient(&irc.Config{ Nick: "nick", Username: "user", Host: "host.com", @@ -250,7 +250,7 @@ func TestHandleIRCTopic(t *testing.T) { res = dispatchMessage(&irc.Message{ Command: irc.TOPIC, Params: []string{"#chan", "the topic"}, - Nick: "bob", + Sender: "bob", }) checkResponse(t, "topic", Topic{ @@ -274,7 +274,7 @@ func TestHandleIRCNoTopic(t *testing.T) { } func TestHandleIRCNames(t *testing.T) { - c := irc.NewClient(irc.Config{ + c := irc.NewClient(&irc.Config{ Nick: "nick", Username: "user", Host: "host.com", @@ -303,7 +303,7 @@ func TestHandleIRCNames(t *testing.T) { } func TestHandleIRCMotd(t *testing.T) { - c := irc.NewClient(irc.Config{ + c := irc.NewClient(&irc.Config{ Nick: "nick", Username: "user", Host: "host.com", @@ -333,7 +333,7 @@ func TestHandleIRCMotd(t *testing.T) { } func TestHandleIRCBadNick(t *testing.T) { - c := irc.NewClient(irc.Config{ + c := irc.NewClient(&irc.Config{ Nick: "nick", Username: "user", Host: "host.com",