|
|
|
@ -40,6 +40,7 @@ const (
|
|
|
|
|
COMMAND_REVEAL = "REVEAL"
|
|
|
|
|
COMMAND_KICK = "KICK"
|
|
|
|
|
COMMAND_BAN = "BAN"
|
|
|
|
|
COMMAND_AUDIT = "AUDIT"
|
|
|
|
|
|
|
|
|
|
// Server admins only
|
|
|
|
|
COMMAND_KILL = "KILL"
|
|
|
|
@ -68,22 +69,26 @@ var permissionLabels = map[int]string{
|
|
|
|
|
PERMISSION_SUPERADMIN: "Super Administrator",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ALL_PERMISSIONS = "Client, Registered Client, VIP, Moderator, Adminsitrator and Super Administrator"
|
|
|
|
|
|
|
|
|
|
var commandRestrictions = map[int][]string{
|
|
|
|
|
PERMISSION_REGISTERED: {COMMAND_TOKEN, COMMAND_USERNAME, COMMAND_PASSWORD, COMMAND_FOUND},
|
|
|
|
|
PERMISSION_MODERATOR: {COMMAND_REVEAL, COMMAND_KICK, COMMAND_BAN},
|
|
|
|
|
PERMISSION_ADMIN: {COMMAND_GRANT},
|
|
|
|
|
PERMISSION_ADMIN: {COMMAND_GRANT, COMMAND_AUDIT},
|
|
|
|
|
PERMISSION_SUPERADMIN: {COMMAND_DROP, COMMAND_KILL, COMMAND_STATS, COMMAND_REHASH, COMMAND_UPGRADE}}
|
|
|
|
|
|
|
|
|
|
var helpDuration = "Duration can be 0 to never expire, or e.g. 30m, 1h, 2d, 3w"
|
|
|
|
|
var commandUsage = map[string][]string{
|
|
|
|
|
COMMAND_HELP: {"[command]",
|
|
|
|
|
"Print info regarding all commands or a specific command"},
|
|
|
|
|
COMMAND_HELP: {"[command|all]",
|
|
|
|
|
"Print usage information regarding a specific command or 'all'",
|
|
|
|
|
"Without a command or 'all', only commands currently available are printed"},
|
|
|
|
|
COMMAND_INFO: {"[channel]",
|
|
|
|
|
"When a channel is specified, prints info including whether it is registered",
|
|
|
|
|
"Without a channel, server info is printed"},
|
|
|
|
|
COMMAND_REGISTER: {"<username> <password>",
|
|
|
|
|
"Create an account, allowing you to found channels and moderate existing channels",
|
|
|
|
|
"See IDENTIFY, FOUND, GRANT"},
|
|
|
|
|
"Create an account",
|
|
|
|
|
"Once you've registered, other users may GRANT permissions to you, or ",
|
|
|
|
|
"See IDENTIFY"},
|
|
|
|
|
COMMAND_IDENTIFY: {"[username] <password>",
|
|
|
|
|
"Identify to a previously registered account",
|
|
|
|
|
"If username is omitted, it will be replaced with your current nick",
|
|
|
|
@ -95,23 +100,29 @@ var commandUsage = map[string][]string{
|
|
|
|
|
COMMAND_PASSWORD: {"<username> <password> <new password> <confirm new password>",
|
|
|
|
|
"Change your password"},
|
|
|
|
|
COMMAND_FOUND: {"<channel>",
|
|
|
|
|
"Register a channel"},
|
|
|
|
|
COMMAND_GRANT: {"<channel> [account] [updated access]",
|
|
|
|
|
"When an account token isn't specified, all permissions are listed",
|
|
|
|
|
"View or update a user's access level by specifying their account token",
|
|
|
|
|
"To remove an account, set their access level to User"},
|
|
|
|
|
COMMAND_REVEAL: {"<channel> [page] [full]",
|
|
|
|
|
"Take ownership of an unfounded channel"},
|
|
|
|
|
COMMAND_GRANT: {"<channel> [account] [permission]",
|
|
|
|
|
"When an account token isn't specified, all accounts with permissions are listed",
|
|
|
|
|
"Specify an account token and permission level to grant that permission",
|
|
|
|
|
"Specify an account token only to view that account's permission",
|
|
|
|
|
"To remove an account's permissions, set their permission to Client",
|
|
|
|
|
"Permissions: " + ALL_PERMISSIONS},
|
|
|
|
|
COMMAND_REVEAL: {"<channel> [page] [all]",
|
|
|
|
|
"Print channel log, allowing KICK/BAN to be used",
|
|
|
|
|
fmt.Sprintf("Results start at page 1, %d per page", CHANNEL_LOGS_PER_PAGE),
|
|
|
|
|
"All log entries are returned when viewing page -1",
|
|
|
|
|
"By default joins and parts are hidden, use 'full' to show them"},
|
|
|
|
|
"Page -1 shows all matching entries",
|
|
|
|
|
"Joins and parts are hidden by default, add 'all' to show them"},
|
|
|
|
|
COMMAND_AUDIT: {"<channel> [page]",
|
|
|
|
|
"Print channel audit log",
|
|
|
|
|
fmt.Sprintf("Results start at page 1, %d per page", CHANNEL_LOGS_PER_PAGE),
|
|
|
|
|
"Page -1 shows all matching entries"},
|
|
|
|
|
COMMAND_KICK: {"<channel> <5 digit log number> [reason]",
|
|
|
|
|
"Kick a user from a channel"},
|
|
|
|
|
COMMAND_BAN: {"<channel> <5 digit log number> <duration> [reason]",
|
|
|
|
|
"Kick and ban a user from a channel",
|
|
|
|
|
helpDuration},
|
|
|
|
|
COMMAND_DROP: {"<channel> <confirm channel>",
|
|
|
|
|
"Delete all channel data, allowing it to be FOUNDed again"},
|
|
|
|
|
"Delete all channel data, allowing it to be founded again"},
|
|
|
|
|
COMMAND_KILL: {"<channel> <5 digit log number> <duration> [reason]",
|
|
|
|
|
"Disconnect and ban a user from the server",
|
|
|
|
|
helpDuration},
|
|
|
|
@ -564,13 +575,13 @@ func (s *Server) handleTopic(channel string, client string, topic string) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) handleMode(c *Client, params []string) {
|
|
|
|
|
// TODO: irssi sends mode <channel> b, send response
|
|
|
|
|
if len(params) == 0 || len(params[0]) == 0 {
|
|
|
|
|
c.sendNotice("Invalid use of MODE")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c == nil {
|
|
|
|
|
if len(params) > 1 && params[1] == "b" {
|
|
|
|
|
c.writeMessage(irc.RPL_ENDOFBANLIST, []string{params[0], "End of Channel Ban List"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -586,9 +597,8 @@ func (s *Server) handleMode(c *Client, params []string) {
|
|
|
|
|
|
|
|
|
|
// Send channel creation time
|
|
|
|
|
c.writeMessage(strings.Join([]string{"329", c.nick, params[0], fmt.Sprintf("%d", int32(ch.created))}, " "), []string{})
|
|
|
|
|
} else if len(params) > 1 && len(params[1]) > 0 && (params[1][0] == '+' || params[1][0] == '-') {
|
|
|
|
|
} else if len(params) > 1 && len(params[1]) > 0 && params[1][0] == '+' || params[1][0] == '-' {
|
|
|
|
|
if !c.canUse(irc.MODE, params[0]) {
|
|
|
|
|
// TODO: Send proper mode denied message
|
|
|
|
|
c.accessDenied(c.permissionRequired(irc.MODE))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@ -683,25 +693,17 @@ func (s *Server) handleMode(c *Client, params []string) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) buildUsage(cl *Client, command string) map[string][]string {
|
|
|
|
|
u := map[string][]string{}
|
|
|
|
|
func (s *Server) sendUsage(cl *Client, command string) {
|
|
|
|
|
command = strings.ToUpper(command)
|
|
|
|
|
for cmd, usage := range commandUsage {
|
|
|
|
|
if command == COMMAND_HELP || cmd == command {
|
|
|
|
|
if cl.canUse(cmd, "") {
|
|
|
|
|
u[cmd] = usage
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return u
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) sendUsage(cl *Client, command string) {
|
|
|
|
|
u := s.buildUsage(cl, command)
|
|
|
|
|
showAll := false
|
|
|
|
|
if command == "ALL" {
|
|
|
|
|
command = COMMAND_HELP
|
|
|
|
|
showAll = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commands := make([]string, 0, len(u))
|
|
|
|
|
for cmd := range u {
|
|
|
|
|
commands := make([]string, 0, len(commandUsage))
|
|
|
|
|
for cmd := range commandUsage {
|
|
|
|
|
commands = append(commands, cmd)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(commands)
|
|
|
|
@ -725,9 +727,11 @@ func (s *Server) sendUsage(cl *Client, command string) {
|
|
|
|
|
for _, permission := range perms {
|
|
|
|
|
printedLabel = false
|
|
|
|
|
for _, cmd := range commands {
|
|
|
|
|
if cl.permissionRequired(cmd) != permission {
|
|
|
|
|
if (i == 0 && containsString(serverCommands, cmd)) || (i == 1 && !containsString(serverCommands, cmd)) || cl.permissionRequired(cmd) != permission {
|
|
|
|
|
continue
|
|
|
|
|
} else if (i == 0 && containsString(serverCommands, cmd)) || (i == 1 && !containsString(serverCommands, cmd)) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !showAll && !cl.canUse(cmd, "") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -736,7 +740,7 @@ func (s *Server) sendUsage(cl *Client, command string) {
|
|
|
|
|
printedLabel = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usage = u[cmd]
|
|
|
|
|
usage = commandUsage[cmd]
|
|
|
|
|
cl.sendMessage(cmd + " " + usage[0])
|
|
|
|
|
for _, ul := range usage[1:] {
|
|
|
|
|
cl.sendMessage(" " + ul)
|
|
|
|
@ -745,14 +749,13 @@ func (s *Server) sendUsage(cl *Client, command string) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// TODO: Cleanup/merge
|
|
|
|
|
for _, cmd := range commands {
|
|
|
|
|
usage = u[cmd]
|
|
|
|
|
|
|
|
|
|
cl.sendMessage(cmd + " " + usage[0])
|
|
|
|
|
if usage, ok := commandUsage[command]; ok {
|
|
|
|
|
cl.sendMessage(command + " " + usage[0])
|
|
|
|
|
for _, ul := range usage[1:] {
|
|
|
|
|
cl.sendMessage(" " + ul)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cl.sendError("Unknown command specified")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -848,6 +851,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Only alphanumeric username
|
|
|
|
|
// TODO: allow duplicate usernames, only return error on existing username and password
|
|
|
|
|
case COMMAND_IDENTIFY:
|
|
|
|
|
if len(params) == 0 || len(params) > 2 {
|
|
|
|
|
s.sendUsage(cl, command)
|
|
|
|
@ -940,7 +944,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
|
|
|
|
|
log.Panicf("%+v", err)
|
|
|
|
|
}
|
|
|
|
|
cl.sendMessage("Password changed successfully")
|
|
|
|
|
case COMMAND_REVEAL:
|
|
|
|
|
case COMMAND_REVEAL, COMMAND_AUDIT:
|
|
|
|
|
// TODO: &#chan shows moderator audit log, & alone shows server admin audit log
|
|
|
|
|
if len(params) == 0 {
|
|
|
|
|
s.sendUsage(cl, command)
|
|
|
|
@ -975,7 +979,11 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.revealChannelLog(params[0], cl.identifier, page, all)
|
|
|
|
|
if command == COMMAND_REVEAL {
|
|
|
|
|
s.revealChannelLog(params[0], cl.identifier, page, all)
|
|
|
|
|
} else {
|
|
|
|
|
// TODO: Audit
|
|
|
|
|
}
|
|
|
|
|
case COMMAND_KICK:
|
|
|
|
|
if len(params) < 2 {
|
|
|
|
|
s.sendUsage(cl, command)
|
|
|
|
@ -1119,7 +1127,7 @@ func (s *Server) handleRead(c *Client) {
|
|
|
|
|
s.killClient(c, "")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if debugMode && (verbose || (len(msg.Command) >= 4 && msg.Command[0:4] != irc.PING && msg.Command[0:4] != irc.PONG)) {
|
|
|
|
|
if debugMode && (verbose || len(msg.Command) < 4 || (msg.Command[0:4] != irc.PING && msg.Command[0:4] != irc.PONG)) {
|
|
|
|
|
log.Printf("%s -> %s", c.identifier, msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1263,11 +1271,7 @@ func (s *Server) handleRead(c *Client) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if msg.Command == irc.MODE {
|
|
|
|
|
if len(msg.Params) == 2 && validChannelPrefix(msg.Params[0]) && msg.Params[1] == "b" {
|
|
|
|
|
c.writeMessage(irc.RPL_ENDOFBANLIST, []string{msg.Params[0], "End of Channel Ban List"})
|
|
|
|
|
} else {
|
|
|
|
|
s.handleMode(c, msg.Params)
|
|
|
|
|
}
|
|
|
|
|
s.handleMode(c, msg.Params)
|
|
|
|
|
} else if msg.Command == irc.TOPIC && len(msg.Params) > 0 && len(msg.Params[0]) > 0 {
|
|
|
|
|
if len(msg.Params) == 1 {
|
|
|
|
|
s.sendTopic(msg.Params[0], c.identifier, false)
|
|
|
|
@ -1308,7 +1312,7 @@ func (s *Server) handleWrite(c *Client) {
|
|
|
|
|
msg.Params = append([]string{c.nick}, msg.Params...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if debugMode && (verbose || (len(msg.Command) >= 4 && msg.Command[0:4] != irc.PING && msg.Command[0:4] != irc.PONG)) {
|
|
|
|
|
if debugMode && (verbose || len(msg.Command) < 4 || (msg.Command[0:4] != irc.PING && msg.Command[0:4] != irc.PONG)) {
|
|
|
|
|
log.Printf("%s <- %s", c.identifier, msg)
|
|
|
|
|
}
|
|
|
|
|
c.writer.Encode(msg)
|
|
|
|
|