ircd/handlers.go

254 lines
6.7 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.cluster.Subscribe(chid, sv.remoteq)
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)
sv.channelRemoveUser(chid, clid)
}
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)
sv.channelRemoveUser(chid, 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) {
}