Channel mode handling implemented
This commit is contained in:
parent
e186d94f42
commit
0b6442a17e
125
server.go
125
server.go
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue