Add channel modes +k and +l
parent
e91d8a4dae
commit
dc0cb8b3c8
10
channel.go
10
channel.go
|
@ -149,3 +149,13 @@ func (c *Channel) HasClient(client string) bool {
|
|||
_, ok := c.clients.Load(client)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *Channel) clientCount() int {
|
||||
ccount := 0
|
||||
c.clients.Range(func(k, v interface{}) bool {
|
||||
ccount++
|
||||
return true
|
||||
})
|
||||
|
||||
return ccount
|
||||
}
|
||||
|
|
28
entity.go
28
entity.go
|
@ -13,7 +13,7 @@ const ENTITY_STATE_TERMINATING = 0
|
|||
const ENTITY_STATE_NORMAL = 1
|
||||
|
||||
const CLIENT_MODES = "cD"
|
||||
const CHANNEL_MODES = "cDimprstz"
|
||||
const CHANNEL_MODES = "cDiklmprstz"
|
||||
const CHANNEL_MODES_ARG = "kl"
|
||||
|
||||
type Entity struct {
|
||||
|
@ -32,6 +32,14 @@ func (e *Entity) Initialize(etype int, identifier string) {
|
|||
e.modes = new(sync.Map)
|
||||
}
|
||||
|
||||
func (e *Entity) getMode(mode string) string {
|
||||
if v, ok := e.modes.Load(mode); ok {
|
||||
return v.(string)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *Entity) getModes() map[string]string {
|
||||
modes := make(map[string]string)
|
||||
e.modes.Range(func(k, v interface{}) bool {
|
||||
|
@ -62,9 +70,21 @@ func (e *Entity) addMode(mode string, value string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Entity) addModes(modes string) {
|
||||
for _, mode := range strings.Split(modes, "") {
|
||||
e.addMode(mode, "")
|
||||
func (e *Entity) addModes(newmodes []string) {
|
||||
if len(newmodes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
p := 1
|
||||
for _, mode := range strings.Split(newmodes[0], "") {
|
||||
if strings.ContainsAny(mode, CHANNEL_MODES_ARG) {
|
||||
if len(newmodes) > p {
|
||||
e.addMode(mode, newmodes[p])
|
||||
p++
|
||||
}
|
||||
} else {
|
||||
e.addMode(mode, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
67
server.go
67
server.go
|
@ -320,7 +320,7 @@ func (s *Server) inChannel(channel string, client string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (s *Server) canAccessChannel(c *Client, channel string) (bool, string) {
|
||||
func (s *Server) canJoin(c *Client, channel string, key string) (bool, string) {
|
||||
dbch, err := db.Channel(channel)
|
||||
if err != nil || dbch.Channel == "" {
|
||||
return false, "invalid channel"
|
||||
|
@ -356,6 +356,23 @@ func (s *Server) canAccessChannel(c *Client, channel string) (bool, string) {
|
|||
}
|
||||
}
|
||||
|
||||
if permission < PERMISSION_VIP {
|
||||
if ch.hasMode("k") && ch.getMode("k") != key {
|
||||
return false, "invalid channel key specified"
|
||||
} else if ch.hasMode("l") {
|
||||
var l int
|
||||
var err error
|
||||
l, err = strconv.Atoi(ch.getMode("l"))
|
||||
if err != nil {
|
||||
l = 0
|
||||
}
|
||||
|
||||
if l > 0 && ch.clientCount() >= l {
|
||||
return false, "limited channel, join again in a few moments"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ch.hasMode("r") {
|
||||
requiredPermission = PERMISSION_REGISTERED
|
||||
reason = "only registered clients are allowed"
|
||||
|
@ -368,7 +385,7 @@ func (s *Server) canAccessChannel(c *Client, channel string) (bool, string) {
|
|||
return permission >= requiredPermission, reason
|
||||
}
|
||||
|
||||
func (s *Server) joinChannel(channel string, client string) {
|
||||
func (s *Server) joinChannel(client string, channel string, key string) {
|
||||
if s.inChannel(channel, client) {
|
||||
return // Already in channel
|
||||
}
|
||||
|
@ -382,14 +399,14 @@ func (s *Server) joinChannel(channel string, client string) {
|
|||
if ch == nil {
|
||||
ch = NewChannel(channel)
|
||||
s.channels.Store(channel, ch)
|
||||
} else if canaccess, reason := s.canAccessChannel(cl, channel); !canaccess {
|
||||
} else if canaccess, reason := s.canJoin(cl, channel, key); !canaccess {
|
||||
errmsg := fmt.Sprintf("Cannot join %s: %s", channel, reason)
|
||||
cl.writeMessage(irc.ERR_INVITEONLYCHAN, []string{channel, errmsg})
|
||||
cl.sendNotice(errmsg)
|
||||
return
|
||||
}
|
||||
|
||||
ch.clients.Store(client, s.clientsInChannel(channel, client)+1)
|
||||
ch.clients.Store(client, s.anonCount(channel, client)+1)
|
||||
cl.write(cl.getPrefix(), irc.JOIN, []string{channel})
|
||||
ch.Log(cl, irc.JOIN, "")
|
||||
|
||||
|
@ -453,7 +470,7 @@ func (s *Server) enforceModes(channel string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Server) clientsInChannel(channel string, client string) int {
|
||||
func (s *Server) anonCount(channel string, client string) int {
|
||||
ch := s.getChannel(channel)
|
||||
cl := s.getClient(client)
|
||||
|
||||
|
@ -461,12 +478,7 @@ func (s *Server) clientsInChannel(channel string, client string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
ccount := 0
|
||||
ch.clients.Range(func(k, v interface{}) bool {
|
||||
ccount++
|
||||
return true
|
||||
})
|
||||
|
||||
ccount := ch.clientCount()
|
||||
if (ch.hasMode("c") || cl.hasMode("c")) && ccount >= 2 {
|
||||
return 2
|
||||
}
|
||||
|
@ -493,7 +505,7 @@ func (s *Server) updateClientCount(channel string, client string, reason string)
|
|||
}
|
||||
|
||||
reasonShown = false
|
||||
chancount := s.clientsInChannel(channel, cl.identifier)
|
||||
chancount := s.anonCount(channel, cl.identifier)
|
||||
|
||||
if ccount < chancount {
|
||||
for i := ccount; i < chancount; i++ {
|
||||
|
@ -539,7 +551,7 @@ func (s *Server) sendNames(channel string, clientname string) {
|
|||
names = append(names, cl.nick)
|
||||
}
|
||||
|
||||
ccount := s.clientsInChannel(channel, clientname)
|
||||
ccount := s.anonCount(channel, clientname)
|
||||
for i := 1; i < ccount; i++ {
|
||||
if cl.capHostInNames {
|
||||
names = append(names, s.getAnonymousPrefix(i).String())
|
||||
|
@ -631,7 +643,7 @@ func (s *Server) handleChannelMode(c *Client, params []string) {
|
|||
}
|
||||
|
||||
if params[1][0] == '+' {
|
||||
ch.addModes(params[1][1:])
|
||||
ch.addModes(params[1:])
|
||||
} else {
|
||||
ch.removeModes(params[1][1:])
|
||||
}
|
||||
|
@ -684,7 +696,7 @@ func (s *Server) handleUserMode(c *Client, params []string) {
|
|||
|
||||
if len(params) > 1 && len(params[1]) > 0 && (params[1][0] == '+' || params[1][0] == '-') {
|
||||
if params[1][0] == '+' {
|
||||
c.addModes(params[1][1:])
|
||||
c.addModes(params[1:])
|
||||
} else {
|
||||
c.removeModes(params[1][1:])
|
||||
}
|
||||
|
@ -890,9 +902,11 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
|
|||
return
|
||||
case COMMAND_INFO:
|
||||
if len(params) > 0 && len(params[0]) > 0 {
|
||||
if canaccess, reason := s.canAccessChannel(cl, params[0]); !canaccess {
|
||||
cl.sendError("Failed to fetch channel INFO, " + reason)
|
||||
return
|
||||
if !s.inChannel(params[0], client) {
|
||||
if canaccess, reason := s.canJoin(cl, params[0], ""); !canaccess {
|
||||
cl.sendError("Failed to fetch channel INFO, " + reason)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
dbch, err := db.Channel(params[0])
|
||||
|
@ -935,9 +949,8 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
|
|||
authSuccess := cl.identify(username, password)
|
||||
if authSuccess {
|
||||
cl.sendNotice("Identified successfully")
|
||||
|
||||
if cl.globalPermission() >= PERMISSION_VIP {
|
||||
s.joinChannel(CHANNEL_SERVER, cl.identifier)
|
||||
s.joinChannel(cl.identifier, CHANNEL_SERVER, "")
|
||||
}
|
||||
|
||||
for clch := range s.getChannels(cl.identifier) {
|
||||
|
@ -1225,9 +1238,9 @@ func (s *Server) handleRead(c *Client) {
|
|||
c.writeMessage(motdcode, []string{" " + motdmsg})
|
||||
}
|
||||
|
||||
s.joinChannel(CHANNEL_LOBBY, c.identifier)
|
||||
s.joinChannel(c.identifier, CHANNEL_LOBBY, "")
|
||||
if c.globalPermission() >= PERMISSION_VIP {
|
||||
s.joinChannel(CHANNEL_SERVER, c.identifier)
|
||||
s.joinChannel(c.identifier, CHANNEL_SERVER, "")
|
||||
}
|
||||
} else if msg.Command == irc.PASS && c.user == "" && len(msg.Params) > 0 && len(msg.Params[0]) > 0 {
|
||||
// TODO: Add auth and multiple failed attempts ban
|
||||
|
@ -1303,7 +1316,7 @@ func (s *Server) handleRead(c *Client) {
|
|||
return true
|
||||
}
|
||||
|
||||
chans[key] = s.clientsInChannel(key, c.identifier)
|
||||
chans[key] = s.anonCount(key, c.identifier)
|
||||
return true
|
||||
})
|
||||
|
||||
|
@ -1315,8 +1328,12 @@ func (s *Server) handleRead(c *Client) {
|
|||
}
|
||||
c.writeMessage(irc.RPL_LISTEND, []string{"End of /LIST"})
|
||||
} else if msg.Command == irc.JOIN && len(msg.Params) > 0 && len(msg.Params[0]) > 0 {
|
||||
key := ""
|
||||
if len(msg.Params) > 1 {
|
||||
key = msg.Params[1]
|
||||
}
|
||||
for _, channel := range strings.Split(msg.Params[0], ",") {
|
||||
s.joinChannel(channel, c.identifier)
|
||||
s.joinChannel(c.identifier, channel, key)
|
||||
}
|
||||
} else if msg.Command == irc.NAMES && len(msg.Params) > 0 && len(msg.Params[0]) > 0 {
|
||||
for _, channel := range strings.Split(msg.Params[0], ",") {
|
||||
|
@ -1326,7 +1343,7 @@ func (s *Server) handleRead(c *Client) {
|
|||
var ccount int
|
||||
for _, channel := range strings.Split(msg.Params[0], ",") {
|
||||
if s.inChannel(channel, c.identifier) {
|
||||
ccount = s.clientsInChannel(channel, c.identifier)
|
||||
ccount = s.anonCount(channel, c.identifier)
|
||||
for i := 0; i < ccount; i++ {
|
||||
var prfx *irc.Prefix
|
||||
if i == 0 {
|
||||
|
|
Loading…
Reference in New Issue