2013-08-24 06:48:28 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c *Client) joinChannel(channelName string) {
|
2013-08-27 17:50:37 +00:00
|
|
|
newChannel := false
|
|
|
|
|
2013-08-27 12:40:51 +00:00
|
|
|
channelKey := strings.ToLower(channelName)
|
|
|
|
channel, exists := c.server.channelMap[channelKey]
|
2013-08-24 06:48:28 +00:00
|
|
|
if exists == false {
|
2016-03-07 09:28:54 +00:00
|
|
|
mode := ChannelMode{secret: true,
|
|
|
|
topicLocked: true,
|
|
|
|
noExternal: true}
|
2013-08-24 06:48:28 +00:00
|
|
|
channel = &Channel{name: channelName,
|
|
|
|
topic: "",
|
2013-08-27 17:50:37 +00:00
|
|
|
clientMap: make(map[string]*Client),
|
2016-03-07 09:28:54 +00:00
|
|
|
modeMap: make(map[string]*ClientMode),
|
|
|
|
mode: mode}
|
2013-08-27 12:40:51 +00:00
|
|
|
c.server.channelMap[channelKey] = channel
|
2013-08-27 17:50:37 +00:00
|
|
|
newChannel = true
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2016-03-19 06:07:18 +00:00
|
|
|
if _, inChannel := channel.clientMap[c.key]; inChannel {
|
2013-08-27 12:44:42 +00:00
|
|
|
//Client is already in the channel, do nothing
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-08-27 17:50:37 +00:00
|
|
|
mode := new(ClientMode)
|
|
|
|
if newChannel {
|
|
|
|
//If they created the channel, make them op
|
|
|
|
mode.operator = true
|
|
|
|
}
|
|
|
|
|
2016-03-19 06:07:18 +00:00
|
|
|
channel.clientMap[c.key] = c
|
|
|
|
channel.modeMap[c.key] = mode
|
2013-08-27 12:40:51 +00:00
|
|
|
c.channelMap[channelKey] = channel
|
2013-08-24 06:48:28 +00:00
|
|
|
|
|
|
|
for _, client := range channel.clientMap {
|
2013-08-30 15:36:41 +00:00
|
|
|
client.reply(rplJoin, c.nick, channel.name)
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if channel.topic != "" {
|
2013-08-30 15:36:41 +00:00
|
|
|
c.reply(rplTopic, channel.name, channel.topic)
|
2013-08-24 06:48:28 +00:00
|
|
|
} else {
|
2013-08-30 15:36:41 +00:00
|
|
|
c.reply(rplNoTopic, channel.name)
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 08:04:04 +00:00
|
|
|
//The capacity sets the max number of nicks to send per message
|
|
|
|
nicks := make([]string, 0, 128)
|
|
|
|
|
2013-08-27 12:40:51 +00:00
|
|
|
for _, client := range channel.clientMap {
|
2013-08-27 17:50:37 +00:00
|
|
|
prefix := ""
|
|
|
|
|
2016-03-19 06:07:18 +00:00
|
|
|
if mode, exists := channel.modeMap[client.key]; exists {
|
2013-08-28 15:38:54 +00:00
|
|
|
prefix = mode.Prefix()
|
2013-08-27 17:50:37 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 08:04:04 +00:00
|
|
|
if len(nicks) >= cap(nicks) {
|
|
|
|
c.reply(rplNames, channelName, strings.Join(nicks, " "))
|
|
|
|
nicks = nicks[:0]
|
|
|
|
}
|
|
|
|
|
2013-08-27 17:50:37 +00:00
|
|
|
nicks = append(nicks, fmt.Sprintf("%s%s", prefix, client.nick))
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 08:04:04 +00:00
|
|
|
if len(nicks) > 0 {
|
|
|
|
c.reply(rplNames, channelName, strings.Join(nicks, " "))
|
|
|
|
}
|
|
|
|
|
|
|
|
c.reply(rplEndOfNames, channelName)
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2013-08-29 20:23:52 +00:00
|
|
|
func (c *Client) partChannel(channelName, reason string) {
|
2013-08-27 12:40:51 +00:00
|
|
|
channelKey := strings.ToLower(channelName)
|
|
|
|
channel, exists := c.server.channelMap[channelKey]
|
2013-08-24 06:48:28 +00:00
|
|
|
if exists == false {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-03-07 18:50:52 +00:00
|
|
|
if _, inChannel := channel.clientMap[c.key]; inChannel == false {
|
2013-08-27 12:44:42 +00:00
|
|
|
//Client isn't in this channel, do nothing
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-08-24 06:48:28 +00:00
|
|
|
//Notify clients of the part
|
|
|
|
for _, client := range channel.clientMap {
|
2013-08-30 15:36:41 +00:00
|
|
|
client.reply(rplPart, c.nick, channel.name, reason)
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2016-03-07 11:28:56 +00:00
|
|
|
delete(c.channelMap, channelKey)
|
2016-03-07 18:50:52 +00:00
|
|
|
delete(channel.modeMap, c.key)
|
|
|
|
delete(channel.clientMap, c.key)
|
2013-08-27 12:40:51 +00:00
|
|
|
|
|
|
|
if len(channel.clientMap) == 0 {
|
2016-03-07 11:28:56 +00:00
|
|
|
delete(c.server.channelMap, channelKey)
|
2013-08-27 12:40:51 +00:00
|
|
|
}
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) disconnect() {
|
|
|
|
c.connected = false
|
|
|
|
c.signalChan <- signalStop
|
|
|
|
}
|
|
|
|
|
|
|
|
//Send a reply to a user with the code specified
|
2013-08-24 19:58:38 +00:00
|
|
|
func (c *Client) reply(code replyCode, args ...string) {
|
2013-08-24 06:48:28 +00:00
|
|
|
if c.connected == false {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch code {
|
|
|
|
case rplWelcome:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 001 %s :Welcome to %s", c.server.name, c.nick, c.server.name)
|
|
|
|
case rplJoin:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s JOIN %s", args[0], args[1])
|
|
|
|
case rplPart:
|
2013-08-29 20:23:52 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s PART %s %s", args[0], args[1], args[2])
|
2013-08-24 06:48:28 +00:00
|
|
|
case rplTopic:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 332 %s %s :%s", c.server.name, c.nick, args[0], args[1])
|
|
|
|
case rplNoTopic:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 331 %s %s :No topic is set", c.server.name, c.nick, args[0])
|
|
|
|
case rplNames:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 353 %s = %s :%s", c.server.name, c.nick, args[0], args[1])
|
2016-03-09 08:04:04 +00:00
|
|
|
case rplEndOfNames:
|
2013-10-21 12:25:39 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 366 %s %s :End of NAMES list", c.server.name, c.nick, args[0])
|
2013-08-24 06:48:28 +00:00
|
|
|
case rplNickChange:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s NICK %s", args[0], args[1])
|
|
|
|
case rplKill:
|
2013-08-29 20:20:34 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s KILL %s A %s", args[0], c.nick, args[1])
|
2013-08-24 06:48:28 +00:00
|
|
|
case rplMsg:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s PRIVMSG %s %s", args[0], args[1], args[2])
|
|
|
|
case rplList:
|
2016-03-13 09:07:16 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 322 %s %s", c.server.name, c.nick, args[0])
|
|
|
|
case rplListEnd:
|
2013-08-24 06:48:28 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 323 %s", c.server.name, c.nick)
|
|
|
|
case rplOper:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 381 %s :You are now an operator", c.server.name, c.nick)
|
2013-08-27 18:34:52 +00:00
|
|
|
case rplChannelModeIs:
|
2013-08-29 16:57:33 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 324 %s %s %s %s", c.server.name, c.nick, args[0], args[1], args[2])
|
2013-08-29 20:10:28 +00:00
|
|
|
case rplKick:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s KICK %s %s %s", args[0], args[1], args[2], args[3])
|
2013-08-30 22:17:54 +00:00
|
|
|
case rplInfo:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 371 %s :%s", c.server.name, c.nick, args[0])
|
2013-09-02 00:55:19 +00:00
|
|
|
case rplVersion:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 351 %s %s", c.server.name, c.nick, args[0])
|
2016-03-13 06:51:10 +00:00
|
|
|
case rplMOTDStart:
|
2013-10-21 12:21:26 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 375 %s :- Message of the day - ", c.server.name, c.nick)
|
2016-03-13 06:51:10 +00:00
|
|
|
case rplMOTD:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 372 %s :- %s", c.server.name, c.nick, args[0])
|
|
|
|
case rplEndOfMOTD:
|
2013-10-21 12:21:26 +00:00
|
|
|
c.outputChan <- fmt.Sprintf(":%s 376 %s :End of MOTD Command", c.server.name, c.nick)
|
2013-10-21 12:34:12 +00:00
|
|
|
case rplPong:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s PONG %s %s", c.server.name, c.nick, c.server.name)
|
2013-08-24 06:48:28 +00:00
|
|
|
case errMoreArgs:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 461 %s :Not enough params", c.server.name, c.nick)
|
|
|
|
case errNoNick:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 431 %s :No nickname given", c.server.name, c.nick)
|
|
|
|
case errInvalidNick:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 432 %s %s :Erronenous nickname", c.server.name, c.nick, args[0])
|
|
|
|
case errNickInUse:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 433 %s %s :Nick already in use", c.server.name, c.nick, args[0])
|
|
|
|
case errAlreadyReg:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 462 :You need a valid nick first", c.server.name)
|
|
|
|
case errNoSuchNick:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 401 %s %s :No such nick/channel", c.server.name, c.nick, args[0])
|
|
|
|
case errUnknownCommand:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 421 %s %s :Unknown command", c.server.name, c.nick, args[0])
|
|
|
|
case errNotReg:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 451 :You have not registered", c.server.name)
|
|
|
|
case errPassword:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 464 %s :Error, password incorrect", c.server.name, c.nick)
|
|
|
|
case errNoPriv:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 481 %s :Permission denied", c.server.name, c.nick)
|
2013-08-27 18:40:14 +00:00
|
|
|
case errCannotSend:
|
|
|
|
c.outputChan <- fmt.Sprintf(":%s 404 %s %s :Cannot send to channel", c.server.name, c.nick, args[0])
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) clientThread() {
|
2013-08-24 19:58:38 +00:00
|
|
|
readSignalChan := make(chan signalCode, 3)
|
|
|
|
writeSignalChan := make(chan signalCode, 3)
|
2013-08-24 06:48:28 +00:00
|
|
|
writeChan := make(chan string, 100)
|
|
|
|
|
2013-09-08 19:35:30 +00:00
|
|
|
c.server.eventChan <- Event{client: c, event: connected}
|
|
|
|
|
2013-08-24 06:48:28 +00:00
|
|
|
go c.readThread(readSignalChan)
|
|
|
|
go c.writeThread(writeSignalChan, writeChan)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
//Part from all channels
|
|
|
|
for channelName := range c.channelMap {
|
2013-08-29 20:23:52 +00:00
|
|
|
c.partChannel(channelName, "Disconnecting")
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
|
2016-03-07 18:50:52 +00:00
|
|
|
delete(c.server.clientMap, c.key)
|
2013-08-24 07:36:57 +00:00
|
|
|
|
|
|
|
c.connection.Close()
|
2013-08-24 06:48:28 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case signal := <-c.signalChan:
|
|
|
|
if signal == signalStop {
|
|
|
|
readSignalChan <- signalStop
|
|
|
|
writeSignalChan <- signalStop
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case line := <-c.outputChan:
|
|
|
|
select {
|
|
|
|
case writeChan <- line:
|
2013-08-24 07:36:57 +00:00
|
|
|
continue
|
2013-08-24 06:48:28 +00:00
|
|
|
default:
|
2013-08-24 07:36:57 +00:00
|
|
|
c.disconnect()
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-08-24 19:58:38 +00:00
|
|
|
func (c *Client) readThread(signalChan chan signalCode) {
|
2013-08-24 06:48:28 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case signal := <-signalChan:
|
|
|
|
if signal == signalStop {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
c.connection.SetReadDeadline(time.Now().Add(time.Second * 3))
|
|
|
|
buf := make([]byte, 512)
|
|
|
|
ln, err := c.connection.Read(buf)
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
c.disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
rawLines := buf[:ln]
|
2016-03-07 22:57:50 +00:00
|
|
|
rawLines = bytes.Replace(rawLines, []byte("\r\n"), []byte("\n"), -1)
|
|
|
|
rawLines = bytes.Replace(rawLines, []byte("\r"), []byte("\n"), -1)
|
|
|
|
lines := bytes.Split(rawLines, []byte("\n"))
|
2013-08-24 06:48:28 +00:00
|
|
|
for _, line := range lines {
|
|
|
|
if len(line) > 0 {
|
2013-09-08 15:24:17 +00:00
|
|
|
c.server.eventChan <- Event{client: c, event: command, input: string(line)}
|
2013-08-24 06:48:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-24 19:58:38 +00:00
|
|
|
func (c *Client) writeThread(signalChan chan signalCode, outputChan chan string) {
|
2013-08-24 06:48:28 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case signal := <-signalChan:
|
|
|
|
if signal == signalStop {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case output := <-outputChan:
|
|
|
|
c.connection.SetWriteDeadline(time.Now().Add(time.Second * 30))
|
2016-03-14 11:17:05 +00:00
|
|
|
if _, err := fmt.Fprintf(c.connection, "%s\r\n", output); err != nil {
|
2013-08-24 06:48:28 +00:00
|
|
|
c.disconnect()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|