268 lines
7.2 KiB
Go
268 lines
7.2 KiB
Go
// vim:ts=4:sts=4:sw=4:noet:tw=72
|
|
|
|
package ircd
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"code.dnix.de/an/irc"
|
|
"code.dnix.de/an/xlog"
|
|
)
|
|
|
|
type commandHook struct {
|
|
HookFn func(sv *Server, msg *irc.Message)
|
|
MinArgs int
|
|
NeedTrail bool
|
|
NeedMode string
|
|
}
|
|
|
|
var svCommandHooks = map[string]commandHook{
|
|
"PRIVMSG": {handleCmdPrivmsg, 1, true, ""},
|
|
"JOIN": {handleCmdJoin, 1, false, ""},
|
|
"PART": {handleCmdPart, 1, false, ""},
|
|
"QUIT": {handleCmdQuit, 0, false, ""},
|
|
"MODE": {handleCmdMode, 1, false, ""},
|
|
"TOPIC": {handleCmdTopic, 1, false, ""},
|
|
"KICK": {handleCmdKick, 2, false, ""},
|
|
"NAMES": {handleCmdNames, 1, false, ""},
|
|
"WHOIS": {handleCmdWhois, 0, false, ""},
|
|
"PING": {handleCmdPing, 1, false, ""},
|
|
"REHASH": {handleCmdRehash, 0, false, "ao"},
|
|
"KILL": {handleCmdKill, 0, false, "ao"},
|
|
/*
|
|
"LIST": {handleCmdList, 0, false, false},
|
|
"VERSION": {handleCmdVersion, 0, false, false},
|
|
"STATS": {handleCmdStats, 0, false, false},
|
|
"TIME": {handleCmdTime, 0, false, false},
|
|
"OPER": {handleCmdOper, 1, false, false},
|
|
"ADMIN": {handleCmdAdmin, 0, false, false},
|
|
"INFO": {handleCmdInfo, 0, false, false},
|
|
"WHO": {handleCmdWho, 0, false, false},
|
|
"WHOWAS": {handleCmdWhowas, 0, false, false},
|
|
"PONG": {handleCmdPong, 0, false, false},
|
|
"ERROR": {handleCmdError, 0, false, false},
|
|
"AWAY": {handleCmdAway, 0, false, false},
|
|
"RESTART": {handleCmdRestart, 0, false, false},
|
|
"SUMMON": {handleCmdSummon, 0, false, false},
|
|
"USERS": {handleCmdUsers, 0, false, false},
|
|
"USERHOST": {handleCmdUserhost, 0, false, false},
|
|
"ISON": {handleCmdIson, 0, false, false},
|
|
*/
|
|
}
|
|
|
|
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.channelCheckPerm(chid, clid, "ohv") {
|
|
sv.sendReply(clid, ERR_CANNOTSENDTOCHAN, chid, "Cannot send to channel")
|
|
return
|
|
}
|
|
if _, exists := sv.chUsers[chid][clid]; !exists {
|
|
sv.sendReply(clid, ERR_CANNOTSENDTOCHAN, chid, "Cannot send to channel")
|
|
return
|
|
}
|
|
}
|
|
sv.sendMsg(msg)
|
|
}
|
|
|
|
func handleCmdJoin(sv *Server, msg *irc.Message) {
|
|
first := false
|
|
clid := strings.ToLower(msg.Pre)
|
|
chid := strings.ToLower(msg.Args[0])
|
|
if !strings.HasPrefix(chid, "#") {
|
|
sv.sendReply(msg.Pre, ERR_NOSUCHCHANNEL, msg.Args[0], "No such channel")
|
|
return
|
|
}
|
|
if _, exists := sv.chUsers[chid]; !exists {
|
|
sv.chUsers[chid] = make(map[string]string)
|
|
sv.chTopics[chid] = ""
|
|
sv.chModes[chid] = make(map[string]bool)
|
|
first = true
|
|
}
|
|
if _, exists := sv.chUsers[chid][clid]; exists {
|
|
return
|
|
}
|
|
sv.chUsers[chid][clid] = ""
|
|
sv.sendMsg(msg)
|
|
// dont proceed further if message was sent by remote origin
|
|
if !sv.localOrigin(msg) {
|
|
return
|
|
}
|
|
sv.sendReply(msg.Pre, RPL_TOPIC, msg.Args[0], sv.chTopics[msg.Args[0]])
|
|
sv.channelNames(msg.Pre, msg.Args[0])
|
|
m, isoper := sv.opers[clid]
|
|
if isoper {
|
|
mode := "o " + clid
|
|
sv.chModes[chid][mode] = true
|
|
sv.sendMsg(irc.M(sv.host, "MODE", chid+" +o "+clid, ""))
|
|
if m == "a" {
|
|
sv.sendMsg(irc.M(sv.host, "PRIVMSG", chid, clid+" is a server administrator"))
|
|
}
|
|
if m == "o" {
|
|
sv.sendMsg(irc.M(sv.host, "PRIVMSG", chid, clid+" is a server operator"))
|
|
}
|
|
return
|
|
}
|
|
if first {
|
|
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) {
|
|
clid := strings.ToLower(msg.Pre)
|
|
chid := strings.ToLower(msg.Args[0])
|
|
if _, exists := sv.chUsers[chid]; !exists {
|
|
return
|
|
}
|
|
if _, exists := sv.chUsers[chid][clid]; !exists {
|
|
return
|
|
}
|
|
sv.sendMsg(msg)
|
|
delete(sv.chUsers[chid], clid)
|
|
//delete(sv.chModes[chid], "q "+clid)
|
|
//delete(sv.chModes[chid], "a "+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 handleCmdMode(sv *Server, msg *irc.Message) {
|
|
if strings.HasPrefix(msg.Args[0], "#") {
|
|
chid := strings.ToLower(msg.Args[0])
|
|
clid := strings.ToLower(msg.Pre)
|
|
if _, exists := sv.chUsers[chid]; !exists {
|
|
return
|
|
}
|
|
if len(msg.Args) < 2 {
|
|
return
|
|
}
|
|
mode := ""
|
|
modeSwitch := msg.Args[1]
|
|
modeTarget := ""
|
|
if len(modeSwitch) < 2 {
|
|
return
|
|
}
|
|
if len(msg.Args) > 2 {
|
|
modeTarget = strings.ToLower(msg.Args[2])
|
|
}
|
|
switch modeSwitch[1] {
|
|
// maybe this can be done more elegant
|
|
case 'o':
|
|
if !sv.channelCheckPerm(chid, clid, "o") {
|
|
goto noPerm
|
|
}
|
|
case 'h':
|
|
if !sv.channelCheckPerm(chid, clid, "o") {
|
|
goto noPerm
|
|
}
|
|
case 'b':
|
|
if !sv.channelCheckPerm(chid, clid, "oh") {
|
|
goto noPerm
|
|
}
|
|
case 'v':
|
|
if !sv.channelCheckPerm(chid, clid, "oh") {
|
|
goto noPerm
|
|
}
|
|
case 'm':
|
|
if !sv.channelCheckPerm(chid, clid, "oh") {
|
|
goto noPerm
|
|
}
|
|
case 't':
|
|
if !sv.channelCheckPerm(chid, clid, "oh") {
|
|
goto noPerm
|
|
}
|
|
default:
|
|
return
|
|
}
|
|
mode = string(modeSwitch[1])
|
|
if modeTarget != "" {
|
|
mode = mode + " " + modeTarget
|
|
}
|
|
if modeSwitch[0] == '+' {
|
|
sv.chModes[chid][mode] = true
|
|
} else {
|
|
delete(sv.chModes[chid], mode)
|
|
}
|
|
sv.sendMsg(msg)
|
|
return
|
|
noPerm:
|
|
sv.sendReply(clid, ERR_CHANOPRIVSNEEDED, chid, "You're not channel operator")
|
|
}
|
|
}
|
|
|
|
func handleCmdTopic(sv *Server, msg *irc.Message) {
|
|
chid := strings.ToLower(msg.Args[0])
|
|
clid := strings.ToLower(msg.Pre)
|
|
if _, exists := sv.chUsers[chid]; !exists {
|
|
sv.sendReply(msg.Pre, ERR_NOSUCHCHANNEL, chid, "No such channel")
|
|
}
|
|
if msg.Trail == "" {
|
|
sv.sendReply(msg.Pre, RPL_TOPIC, chid, sv.chTopics[chid])
|
|
} else {
|
|
if sv.channelCheckMode(chid, "t") &&
|
|
!sv.channelCheckPerm(chid, clid, "oh") {
|
|
sv.sendReply(clid, ERR_CHANOPRIVSNEEDED, chid, "You're not channel operator")
|
|
return
|
|
}
|
|
sv.chTopics[chid] = msg.Trail
|
|
sv.sendMsg(msg)
|
|
//sv.sendReply(msg.Pre, RPL_TOPIC, ch, msg.Trail)
|
|
}
|
|
}
|
|
|
|
func handleCmdKick(sv *Server, msg *irc.Message) {
|
|
chid := strings.ToLower(msg.Args[0])
|
|
clid := strings.ToLower(msg.Pre)
|
|
target := strings.ToLower(msg.Args[1])
|
|
if !sv.channelCheckPerm(chid, clid, "oh") {
|
|
sv.sendReply(clid, ERR_CHANOPRIVSNEEDED, chid, "You're not channel operator")
|
|
}
|
|
sv.sendMsg(msg)
|
|
delete(sv.chUsers[chid], target)
|
|
//delete(sv.chModes[chid], "q "+target)
|
|
//delete(sv.chModes[chid], "a "+target)
|
|
delete(sv.chModes[chid], "o "+target)
|
|
delete(sv.chModes[chid], "h "+target)
|
|
delete(sv.chModes[chid], "v "+target)
|
|
}
|
|
|
|
func handleCmdNames(sv *Server, msg *irc.Message) {
|
|
chid := strings.ToLower(msg.Args[0])
|
|
if _, exists := sv.chUsers[chid]; !exists {
|
|
sv.sendReply(msg.Pre, ERR_NOSUCHCHANNEL, chid, "No such channel")
|
|
}
|
|
sv.channelNames(msg.Pre, chid)
|
|
}
|
|
|
|
func handleCmdWhois(sv *Server, msg *irc.Message) {
|
|
sv.sendReply(msg.Pre, RPL_WHOISUSER, "nick user host *", "real name")
|
|
}
|
|
|
|
func handleCmdPing(sv *Server, msg *irc.Message) {
|
|
sv.sendReply(msg.Pre, "PONG", msg.Args[0], "")
|
|
}
|
|
|
|
func handleCmdRehash(sv *Server, msg *irc.Message) {
|
|
sv.loadConfig()
|
|
sv.sendReply(msg.Pre, RPL_REHASHING, "", "Rehashing")
|
|
xlog.Info("Rehashing")
|
|
}
|
|
|
|
func handleCmdKill(sv *Server, msg *irc.Message) {
|
|
}
|