Channel mode handling implemented

This commit is contained in:
Andreas Neue 2016-07-31 17:24:58 +02:00
parent e186d94f42
commit 0b6442a17e
1 changed files with 108 additions and 17 deletions

125
server.go
View File

@ -37,6 +37,7 @@ type Server struct {
motd string motd string
clients map[string]Client clients map[string]Client
clModes map[string]string
chUsers map[string]map[string]string chUsers map[string]map[string]string
chTopics map[string]string chTopics map[string]string
@ -63,6 +64,7 @@ func NewServer(configPath, software, version string) *Server {
sv.delq = make(chan Client, 128) sv.delq = make(chan Client, 128)
sv.clients = make(map[string]Client) sv.clients = make(map[string]Client)
sv.clModes = make(map[string]string)
sv.chUsers = make(map[string]map[string]string) sv.chUsers = make(map[string]map[string]string)
sv.chTopics = make(map[string]string) sv.chTopics = make(map[string]string)
@ -295,42 +297,65 @@ func (sv *Server) sendLogon(nick string) {
sv.sendReply(nick, RPL_ENDOFMOTD, "", "End of MOTD command") sv.sendReply(nick, RPL_ENDOFMOTD, "", "End of MOTD command")
} }
// Send channel name list to client
func (sv *Server) channelNames(nick, ch string) { func (sv *Server) channelNames(nick, ch string) {
chid := strings.ToLower(ch) chid := strings.ToLower(ch)
if _, exists := sv.chUsers[chid]; !exists { if _, exists := sv.chUsers[chid]; !exists {
return return
} }
names := "" names := ""
for clid, mode := range sv.chUsers[chid] { for clid, _ := range sv.chUsers[chid] {
name := sv.clients[clid].Name() name := sv.clients[clid].Name()
if names != "" { if names != "" {
names += " " names += " "
} }
names = names + mode + name modeFlags := "ohv"
modeChars := "@%+"
for i, mf := range modeFlags {
if _, exists := sv.chModes[chid][string(mf)+" "+clid]; exists {
name = string(modeChars[i]) + name
break
}
}
names = names + name
}
chunks := len(strings.Split(names, " "))/8 + 1
nameList := strings.SplitN(names, " ", chunks)
for _, nameSlice := range nameList {
sv.sendReply(nick, RPL_NAMEREPLY, "= "+ch, nameSlice)
} }
sv.sendReply(nick, RPL_NAMEREPLY, "= "+ch, names)
sv.sendReply(nick, RPL_ENDOFNAMES, ch, "End of /NAMES list") sv.sendReply(nick, RPL_ENDOFNAMES, ch, "End of /NAMES list")
} }
// Check if mode exists for the specified channel
func (sv *Server) channelCheckMode(chid, mode string) bool {
if _, exists := sv.chModes[chid]; !exists {
return false
}
if _, exists := sv.chModes[chid][mode]; !exists {
return false
}
return true
}
type commandHook struct { type commandHook struct {
HookFn func(sv *Server, msg *irc.Message) HookFn func(sv *Server, msg *irc.Message)
MinArgs int MinArgs int
NeedTrail bool NeedTrail bool
NeedOper bool NeedMode string
NeedAuth bool
} }
var svCommandHooks = map[string]commandHook{ var svCommandHooks = map[string]commandHook{
"PRIVMSG": {handleCmdPrivmsg, 1, true, false, false}, "PRIVMSG": {handleCmdPrivmsg, 1, true, ""},
"JOIN": {handleCmdJoin, 1, false, false, false}, "JOIN": {handleCmdJoin, 1, false, ""},
"PART": {handleCmdPart, 1, false, false, false}, "PART": {handleCmdPart, 1, false, ""},
"QUIT": {handleCmdQuit, 0, false, false, false}, "QUIT": {handleCmdQuit, 0, false, ""},
"MODE": {handleCmdMode, 1, false, false, false}, "MODE": {handleCmdMode, 1, false, ""},
"TOPIC": {handleCmdTopic, 1, false, false, false}, "TOPIC": {handleCmdTopic, 1, false, ""},
"NAMES": {handleCmdNames, 1, false, false, false}, "NAMES": {handleCmdNames, 1, false, ""},
"WHOIS": {handleCmdWhois, 0, false, false, false}, "WHOIS": {handleCmdWhois, 0, false, ""},
"PING": {handleCmdPing, 1, false, false, false}, "PING": {handleCmdPing, 1, false, ""},
"REHASH": {handleCmdRehash, 0, false, false, false}, "REHASH": {handleCmdRehash, 0, false, "ao"},
/* /*
"LIST": {handleCmdList, 0, false, false}, "LIST": {handleCmdList, 0, false, false},
"VERSION": {handleCmdVersion, 0, false, false}, "VERSION": {handleCmdVersion, 0, false, false},
@ -354,16 +379,26 @@ var svCommandHooks = map[string]commandHook{
} }
func handleCmdPrivmsg(sv *Server, msg *irc.Message) { func handleCmdPrivmsg(sv *Server, msg *irc.Message) {
if strings.HasPrefix(msg.Args[0], "#") {
clid := strings.ToLower(msg.Pre)
chid := strings.ToLower(msg.Args[0])
if sv.channelCheckMode(chid, "m") &&
!sv.channelCheckMode(chid, "v "+clid) {
return
}
}
sv.sendMsg(msg) sv.sendMsg(msg)
} }
func handleCmdJoin(sv *Server, msg *irc.Message) { func handleCmdJoin(sv *Server, msg *irc.Message) {
first := false
clid := strings.ToLower(msg.Pre) clid := strings.ToLower(msg.Pre)
chid := strings.ToLower(msg.Args[0]) chid := strings.ToLower(msg.Args[0])
if _, exists := sv.chUsers[chid]; !exists { if _, exists := sv.chUsers[chid]; !exists {
sv.chUsers[chid] = make(map[string]string) sv.chUsers[chid] = make(map[string]string)
sv.chTopics[chid] = "" sv.chTopics[chid] = ""
sv.chModes[chid] = make(map[string]bool) sv.chModes[chid] = make(map[string]bool)
first = true
} }
if _, exists := sv.chUsers[chid][clid]; exists { if _, exists := sv.chUsers[chid][clid]; exists {
return return
@ -372,8 +407,16 @@ func handleCmdJoin(sv *Server, msg *irc.Message) {
sv.sendMsg(msg) sv.sendMsg(msg)
sv.sendReply(msg.Pre, RPL_TOPIC, msg.Args[0], sv.chTopics[msg.Args[0]]) sv.sendReply(msg.Pre, RPL_TOPIC, msg.Args[0], sv.chTopics[msg.Args[0]])
sv.channelNames(msg.Pre, msg.Args[0]) sv.channelNames(msg.Pre, msg.Args[0])
if !first {
return
}
mode := "o " + clid
sv.chModes[chid][mode] = true
sv.sendMsg(irc.M(sv.host, "MODE", chid+" +o "+clid, ""))
} }
// Handle user parting the channel and delete channel if last user has
// left
func handleCmdPart(sv *Server, msg *irc.Message) { func handleCmdPart(sv *Server, msg *irc.Message) {
clid := strings.ToLower(msg.Pre) clid := strings.ToLower(msg.Pre)
chid := strings.ToLower(msg.Args[0]) chid := strings.ToLower(msg.Args[0])
@ -385,7 +428,14 @@ func handleCmdPart(sv *Server, msg *irc.Message) {
} }
sv.sendMsg(msg) sv.sendMsg(msg)
delete(sv.chUsers[chid], clid) delete(sv.chUsers[chid], clid)
delete(sv.chModes[chid], "o "+clid)
delete(sv.chModes[chid], "h "+clid)
delete(sv.chModes[chid], "v "+clid)
if len(sv.chUsers[chid]) == 0 {
delete(sv.chUsers, chid)
delete(sv.chTopics, chid)
delete(sv.chModes, chid)
}
} }
func handleCmdQuit(sv *Server, msg *irc.Message) { func handleCmdQuit(sv *Server, msg *irc.Message) {
@ -395,29 +445,70 @@ func handleCmdQuit(sv *Server, msg *irc.Message) {
func handleCmdMode(sv *Server, msg *irc.Message) { func handleCmdMode(sv *Server, msg *irc.Message) {
if strings.HasPrefix(msg.Args[0], "#") { if strings.HasPrefix(msg.Args[0], "#") {
chid := strings.ToLower(msg.Args[0]) chid := strings.ToLower(msg.Args[0])
clid := strings.ToLower(msg.Pre)
if _, exists := sv.chUsers[chid]; !exists { if _, exists := sv.chUsers[chid]; !exists {
return return
} }
if len(msg.Args) < 2 { if len(msg.Args) < 2 {
return return
} }
modeFlag := strings.ToLower(msg.Args[1]) modeFlag := msg.Args[1]
if len(msg.Args) < 3 { if len(msg.Args) < 3 {
//modeTar := "" //modeTar := ""
} else { } else {
//modeTar := strings.ToLower(msg.Args[2]) //modeTar := strings.ToLower(msg.Args[2])
} }
switch modeFlag { switch modeFlag {
// maybe this can be done more elegant
case "+o": case "+o":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
case "-o": case "-o":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
case "+h": case "+h":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
case "-h": case "-h":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
case "+b": case "+b":
if !sv.channelCheckMode(chid, "o "+clid) &&
!sv.channelCheckMode(chid, "h "+clid) {
goto noPerm
}
case "-b": case "-b":
if !sv.channelCheckMode(chid, "o "+clid) &&
!sv.channelCheckMode(chid, "h "+clid) {
goto noPerm
}
case "+v": case "+v":
if !sv.channelCheckMode(chid, "o "+clid) &&
!sv.channelCheckMode(chid, "h "+clid) {
goto noPerm
}
case "-v": case "-v":
if !sv.channelCheckMode(chid, "o "+clid) &&
!sv.channelCheckMode(chid, "h "+clid) {
goto noPerm
}
case "+m":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
case "-m":
if !sv.channelCheckMode(chid, "o "+clid) {
goto noPerm
}
} }
sv.sendMsg(msg) sv.sendMsg(msg)
return
noPerm:
sv.sendReply(clid, ERR_CHANOPRIVSNEEDED, chid, "You're not channel operator")
} }
} }