2012-04-18 03:16:57 +02:00
|
|
|
package irc
|
|
|
|
|
2012-12-09 21:51:50 +01:00
|
|
|
import (
|
|
|
|
"errors"
|
2013-05-11 22:55:01 +02:00
|
|
|
"fmt"
|
2014-02-21 06:09:56 +01:00
|
|
|
"regexp"
|
2012-12-09 21:51:50 +01:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
type editableCommand interface {
|
2013-05-09 18:12:03 +02:00
|
|
|
Command
|
2014-02-17 08:29:11 +01:00
|
|
|
SetCode(StringCode)
|
2014-02-09 08:51:51 +01:00
|
|
|
SetClient(*Client)
|
2013-05-09 18:12:03 +02:00
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
type parseCommandFunc func([]string) (editableCommand, error)
|
|
|
|
|
2012-12-17 04:13:53 +01:00
|
|
|
var (
|
2013-05-09 20:05:10 +02:00
|
|
|
NotEnoughArgsError = errors.New("not enough arguments")
|
|
|
|
ErrParseCommand = errors.New("failed to parse message")
|
2014-02-17 08:29:11 +01:00
|
|
|
parseCommandFuncs = map[StringCode]parseCommandFunc{
|
|
|
|
AWAY: NewAwayCommand,
|
|
|
|
CAP: NewCapCommand,
|
2014-02-23 19:04:31 +01:00
|
|
|
DEBUG: NewDebugCommand,
|
2014-02-17 08:29:11 +01:00
|
|
|
ISON: NewIsOnCommand,
|
|
|
|
JOIN: NewJoinCommand,
|
|
|
|
KICK: NewKickCommand,
|
2014-02-17 08:51:27 +01:00
|
|
|
LIST: NewListCommand,
|
2014-02-17 08:29:11 +01:00
|
|
|
MODE: NewModeCommand,
|
|
|
|
MOTD: NewMOTDCommand,
|
2014-02-18 06:02:03 +01:00
|
|
|
NAMES: NewNamesCommand,
|
2014-02-17 08:29:11 +01:00
|
|
|
NICK: NewNickCommand,
|
|
|
|
NOTICE: NewNoticeCommand,
|
|
|
|
OPER: NewOperCommand,
|
|
|
|
PART: NewPartCommand,
|
|
|
|
PASS: NewPassCommand,
|
|
|
|
PING: NewPingCommand,
|
|
|
|
PONG: NewPongCommand,
|
|
|
|
PRIVMSG: NewPrivMsgCommand,
|
|
|
|
PROXY: NewProxyCommand,
|
|
|
|
QUIT: NewQuitCommand,
|
|
|
|
TOPIC: NewTopicCommand,
|
2014-02-18 07:10:48 +01:00
|
|
|
USER: NewUserCommand,
|
2014-02-17 08:29:11 +01:00
|
|
|
WHO: NewWhoCommand,
|
|
|
|
WHOIS: NewWhoisCommand,
|
2012-12-17 04:13:53 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2013-05-09 20:05:10 +02:00
|
|
|
type BaseCommand struct {
|
|
|
|
client *Client
|
2014-02-17 08:29:11 +01:00
|
|
|
code StringCode
|
2013-05-09 20:05:10 +02:00
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (command *BaseCommand) Client() *Client {
|
2013-05-11 22:55:01 +02:00
|
|
|
return command.client
|
2013-05-09 20:05:10 +02:00
|
|
|
}
|
|
|
|
|
2014-02-09 08:51:51 +01:00
|
|
|
func (command *BaseCommand) SetClient(c *Client) {
|
|
|
|
command.client = c
|
2013-05-09 20:05:10 +02:00
|
|
|
}
|
|
|
|
|
2014-02-17 08:29:11 +01:00
|
|
|
func (command *BaseCommand) Code() StringCode {
|
|
|
|
return command.code
|
2014-02-15 03:28:36 +01:00
|
|
|
}
|
|
|
|
|
2014-02-17 08:29:11 +01:00
|
|
|
func (command *BaseCommand) SetCode(code StringCode) {
|
|
|
|
command.code = code
|
2014-02-15 03:28:36 +01:00
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (command *BaseCommand) Source() Identifier {
|
2014-02-15 03:28:36 +01:00
|
|
|
return command.Client()
|
2013-06-03 07:07:50 +02:00
|
|
|
}
|
|
|
|
|
2014-02-15 03:28:36 +01:00
|
|
|
func ParseCommand(line string) (cmd editableCommand, err error) {
|
2014-02-17 08:29:11 +01:00
|
|
|
code, args := parseLine(line)
|
|
|
|
constructor := parseCommandFuncs[code]
|
2012-12-17 04:13:53 +01:00
|
|
|
if constructor == nil {
|
2014-02-17 08:29:11 +01:00
|
|
|
cmd = NewUnknownCommand(args)
|
2014-02-15 03:28:36 +01:00
|
|
|
} else {
|
|
|
|
cmd, err = constructor(args)
|
2012-12-17 04:13:53 +01:00
|
|
|
}
|
2014-02-15 03:28:36 +01:00
|
|
|
if cmd != nil {
|
2014-02-17 08:29:11 +01:00
|
|
|
cmd.SetCode(code)
|
2014-02-15 03:28:36 +01:00
|
|
|
}
|
|
|
|
return
|
2012-12-17 04:13:53 +01:00
|
|
|
}
|
|
|
|
|
2014-02-21 06:09:56 +01:00
|
|
|
var (
|
|
|
|
spacesExpr = regexp.MustCompile(` +`)
|
|
|
|
)
|
|
|
|
|
2012-12-17 04:13:53 +01:00
|
|
|
func parseArg(line string) (arg string, rest string) {
|
|
|
|
if line == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(line, ":") {
|
|
|
|
arg = line[1:]
|
|
|
|
} else {
|
2014-02-21 06:09:56 +01:00
|
|
|
parts := spacesExpr.Split(line, 2)
|
2012-12-17 04:13:53 +01:00
|
|
|
arg = parts[0]
|
|
|
|
if len(parts) > 1 {
|
|
|
|
rest = parts[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-02-17 08:29:11 +01:00
|
|
|
func parseLine(line string) (command StringCode, args []string) {
|
2012-12-17 04:13:53 +01:00
|
|
|
args = make([]string, 0)
|
|
|
|
for arg, rest := parseArg(line); arg != ""; arg, rest = parseArg(rest) {
|
2014-02-21 06:09:56 +01:00
|
|
|
if arg == "" {
|
|
|
|
continue
|
|
|
|
}
|
2012-12-17 04:13:53 +01:00
|
|
|
args = append(args, arg)
|
|
|
|
}
|
2014-02-17 07:22:46 +01:00
|
|
|
if len(args) > 0 {
|
2014-02-17 08:29:11 +01:00
|
|
|
command, args = StringCode(strings.ToUpper(args[0])), args[1:]
|
2014-02-17 07:22:46 +01:00
|
|
|
}
|
2012-12-17 04:13:53 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// <command> [args...]
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type UnknownCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2014-02-15 03:28:36 +01:00
|
|
|
args []string
|
2012-12-09 07:54:58 +01:00
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *UnknownCommand) String() string {
|
2014-02-17 08:29:11 +01:00
|
|
|
return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Code(), cmd.args)
|
2013-05-12 03:28:18 +02:00
|
|
|
}
|
|
|
|
|
2014-02-17 08:29:11 +01:00
|
|
|
func NewUnknownCommand(args []string) *UnknownCommand {
|
2012-12-15 23:34:20 +01:00
|
|
|
return &UnknownCommand{
|
2014-02-15 03:28:36 +01:00
|
|
|
args: args,
|
2012-12-15 23:34:20 +01:00
|
|
|
}
|
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
|
2012-12-13 08:27:17 +01:00
|
|
|
// PING <server1> [ <server2> ]
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type PingCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
server string
|
|
|
|
server2 string
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *PingCommand) String() string {
|
2013-05-11 22:55:01 +02:00
|
|
|
return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewPingCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) < 1 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
msg := &PingCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
server: args[0],
|
2012-12-13 08:27:17 +01:00
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) > 1 {
|
|
|
|
msg.server2 = args[1]
|
|
|
|
}
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2012-12-13 08:27:17 +01:00
|
|
|
// PONG <server> [ <server2> ]
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type PongCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
server1 string
|
|
|
|
server2 string
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *PongCommand) String() string {
|
2013-05-11 22:55:01 +02:00
|
|
|
return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewPongCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) < 1 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
message := &PongCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
server1: args[0],
|
2012-12-15 23:34:20 +01:00
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) > 1 {
|
|
|
|
message.server2 = args[1]
|
|
|
|
}
|
|
|
|
return message, nil
|
|
|
|
}
|
|
|
|
|
2012-12-10 05:24:53 +01:00
|
|
|
// PASS <password>
|
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type PassCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-10 05:24:53 +01:00
|
|
|
password string
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *PassCommand) String() string {
|
|
|
|
return fmt.Sprintf("PASS(password=%s)", cmd.password)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewPassCommand(args []string) (editableCommand, error) {
|
2012-12-10 05:24:53 +01:00
|
|
|
if len(args) < 1 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
return &PassCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
password: args[0],
|
2012-12-12 07:34:22 +01:00
|
|
|
}, nil
|
2012-12-10 05:24:53 +01:00
|
|
|
}
|
|
|
|
|
2012-12-13 08:27:17 +01:00
|
|
|
// NICK <nickname>
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type NickCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
nickname string
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (m *NickCommand) String() string {
|
2013-05-11 22:55:01 +02:00
|
|
|
return fmt.Sprintf("NICK(nickname=%s)", m.nickname)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewNickCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) != 1 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
return &NickCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
nickname: args[0],
|
2012-12-13 08:27:17 +01:00
|
|
|
}, nil
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
|
|
|
|
2014-02-18 07:10:48 +01:00
|
|
|
type UserCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2014-02-18 07:10:48 +01:00
|
|
|
username string
|
2012-12-09 07:54:58 +01:00
|
|
|
realname string
|
2012-04-18 03:16:57 +02:00
|
|
|
}
|
|
|
|
|
2014-02-18 07:10:48 +01:00
|
|
|
// USER <username> <hostname> <servername> <realname>
|
|
|
|
type RFC1459UserCommand struct {
|
|
|
|
UserCommand
|
|
|
|
hostname string
|
|
|
|
servername string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *RFC1459UserCommand) String() string {
|
|
|
|
return fmt.Sprintf("USER(username=%s, hostname=%s, servername=%s, realname=%s)",
|
|
|
|
cmd.username, cmd.hostname, cmd.servername, cmd.realname)
|
|
|
|
}
|
|
|
|
|
|
|
|
// USER <user> <mode> <unused> <realname>
|
|
|
|
type RFC2812UserCommand struct {
|
|
|
|
UserCommand
|
|
|
|
mode uint8
|
|
|
|
unused string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *RFC2812UserCommand) String() string {
|
|
|
|
return fmt.Sprintf("USER(username=%s, mode=%d, unused=%s, realname=%s)",
|
|
|
|
cmd.username, cmd.mode, cmd.unused, cmd.realname)
|
2013-05-11 22:55:01 +02:00
|
|
|
}
|
|
|
|
|
2014-02-18 07:10:48 +01:00
|
|
|
func (cmd *RFC2812UserCommand) Flags() []UserMode {
|
|
|
|
flags := make([]UserMode, 0)
|
|
|
|
if (cmd.mode & 4) == 4 {
|
|
|
|
flags = append(flags, WallOps)
|
|
|
|
}
|
|
|
|
if (cmd.mode & 8) == 8 {
|
|
|
|
flags = append(flags, Invisible)
|
|
|
|
}
|
|
|
|
return flags
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewUserCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) != 4 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
|
|
|
mode, err := strconv.ParseUint(args[1], 10, 8)
|
|
|
|
if err == nil {
|
2014-02-18 07:10:48 +01:00
|
|
|
msg := &RFC2812UserCommand{
|
|
|
|
mode: uint8(mode),
|
|
|
|
unused: args[2],
|
|
|
|
}
|
|
|
|
msg.username = args[0]
|
|
|
|
msg.realname = args[3]
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
msg := &RFC1459UserCommand{
|
|
|
|
hostname: args[1],
|
|
|
|
servername: args[2],
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2014-02-18 07:10:48 +01:00
|
|
|
msg.username = args[0]
|
|
|
|
msg.realname = args[3]
|
2012-12-09 21:51:50 +01:00
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
// QUIT [ <Quit Command> ]
|
2012-04-18 03:16:57 +02:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type QuitCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
message string
|
2012-04-18 03:16:57 +02:00
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *QuitCommand) String() string {
|
2013-05-11 22:55:01 +02:00
|
|
|
return fmt.Sprintf("QUIT(message=%s)", cmd.message)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewQuitCommand(args []string) (editableCommand, error) {
|
2013-06-03 07:07:50 +02:00
|
|
|
msg := &QuitCommand{}
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) > 0 {
|
|
|
|
msg.message = args[0]
|
|
|
|
}
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2012-12-10 05:24:53 +01:00
|
|
|
// JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type JoinCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-17 04:13:53 +01:00
|
|
|
channels map[string]string
|
2012-12-09 07:54:58 +01:00
|
|
|
zero bool
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *JoinCommand) String() string {
|
|
|
|
return fmt.Sprintf("JOIN(channels=%s, zero=%t)", cmd.channels, cmd.zero)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewJoinCommand(args []string) (editableCommand, error) {
|
2012-12-15 23:34:20 +01:00
|
|
|
msg := &JoinCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
channels: make(map[string]string),
|
2012-12-17 04:13:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(args) == 0 {
|
|
|
|
return nil, NotEnoughArgsError
|
2012-12-13 08:27:17 +01:00
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
|
2012-12-17 04:13:53 +01:00
|
|
|
if args[0] == "0" {
|
|
|
|
msg.zero = true
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
channels := strings.Split(args[0], ",")
|
|
|
|
keys := make([]string, len(channels))
|
|
|
|
if len(args) > 1 {
|
|
|
|
for i, key := range strings.Split(args[1], ",") {
|
|
|
|
keys[i] = key
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
|
|
|
}
|
2012-12-17 04:13:53 +01:00
|
|
|
for i, channel := range channels {
|
|
|
|
msg.channels[channel] = keys[i]
|
|
|
|
}
|
|
|
|
|
2012-12-09 21:51:50 +01:00
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
// PART <channel> *( "," <channel> ) [ <Part Command> ]
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type PartCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
channels []string
|
|
|
|
message string
|
|
|
|
}
|
|
|
|
|
2014-02-09 02:53:06 +01:00
|
|
|
func (cmd *PartCommand) Message() string {
|
|
|
|
if cmd.message == "" {
|
|
|
|
return cmd.Source().Nick()
|
|
|
|
}
|
|
|
|
return cmd.message
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *PartCommand) String() string {
|
|
|
|
return fmt.Sprintf("PART(channels=%s, message=%s)", cmd.channels, cmd.message)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewPartCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) < 1 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
msg := &PartCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
channels: strings.Split(args[0], ","),
|
2012-12-13 08:27:17 +01:00
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) > 1 {
|
|
|
|
msg.message = args[1]
|
|
|
|
}
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2012-12-13 08:27:17 +01:00
|
|
|
// PRIVMSG <target> <message>
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type PrivMsgCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-09 07:54:58 +01:00
|
|
|
target string
|
|
|
|
message string
|
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *PrivMsgCommand) String() string {
|
2013-05-11 22:55:01 +02:00
|
|
|
return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewPrivMsgCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) < 2 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
return &PrivMsgCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
target: args[0],
|
|
|
|
message: args[1],
|
2012-12-09 21:51:50 +01:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2012-12-09 23:59:28 +01:00
|
|
|
// TOPIC [newtopic]
|
2012-12-09 07:54:58 +01:00
|
|
|
|
2012-12-15 23:34:20 +01:00
|
|
|
type TopicCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2014-02-13 03:14:19 +01:00
|
|
|
channel string
|
|
|
|
setTopic bool
|
|
|
|
topic string
|
2012-12-09 07:54:58 +01:00
|
|
|
}
|
|
|
|
|
2013-05-12 03:28:18 +02:00
|
|
|
func (cmd *TopicCommand) String() string {
|
|
|
|
return fmt.Sprintf("TOPIC(channel=%s, topic=%s)", cmd.channel, cmd.topic)
|
|
|
|
}
|
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewTopicCommand(args []string) (editableCommand, error) {
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) < 1 {
|
2012-12-10 05:24:53 +01:00
|
|
|
return nil, NotEnoughArgsError
|
2012-12-09 21:51:50 +01:00
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
msg := &TopicCommand{
|
2013-06-03 07:07:50 +02:00
|
|
|
channel: args[0],
|
2012-12-13 08:27:17 +01:00
|
|
|
}
|
2012-12-09 21:51:50 +01:00
|
|
|
if len(args) > 1 {
|
2014-02-13 03:14:19 +01:00
|
|
|
msg.setTopic = true
|
2012-12-09 21:51:50 +01:00
|
|
|
msg.topic = args[1]
|
|
|
|
}
|
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2014-02-08 23:20:23 +01:00
|
|
|
type ModeChange struct {
|
2014-02-09 07:06:10 +01:00
|
|
|
mode UserMode
|
2014-02-09 07:42:14 +01:00
|
|
|
op ModeOp
|
2014-02-08 23:20:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (change *ModeChange) String() string {
|
2014-02-09 07:42:14 +01:00
|
|
|
return fmt.Sprintf("%s%s", change.op, change.mode)
|
2014-02-08 23:20:23 +01:00
|
|
|
}
|
|
|
|
|
2014-02-16 04:49:20 +01:00
|
|
|
type ModeChanges []ModeChange
|
|
|
|
|
|
|
|
func (changes ModeChanges) String() string {
|
|
|
|
if len(changes) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
op := changes[0].op
|
|
|
|
str := changes[0].op.String()
|
|
|
|
for _, change := range changes {
|
|
|
|
if change.op == op {
|
|
|
|
str += change.mode.String()
|
|
|
|
} else {
|
|
|
|
op = change.op
|
|
|
|
str += " " + change.op.String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
2012-12-17 04:13:53 +01:00
|
|
|
type ModeCommand struct {
|
2013-05-09 18:12:03 +02:00
|
|
|
BaseCommand
|
2012-12-17 04:13:53 +01:00
|
|
|
nickname string
|
2014-02-18 18:45:10 +01:00
|
|
|
changes ModeChanges
|
2012-12-10 05:24:53 +01:00
|
|
|
}
|
|
|
|
|
2014-02-09 07:42:14 +01:00
|
|
|
// MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
|
|
|
|
func NewUserModeCommand(args []string) (editableCommand, error) {
|
|
|
|
cmd := &ModeCommand{
|
|
|
|
nickname: args[0],
|
2014-02-18 18:45:10 +01:00
|
|
|
changes: make(ModeChanges, 0),
|
2014-02-09 07:42:14 +01:00
|
|
|
}
|
2014-02-08 23:20:23 +01:00
|
|
|
|
2014-02-09 07:42:14 +01:00
|
|
|
for _, modeChange := range args[1:] {
|
|
|
|
op := ModeOp(modeChange[0])
|
|
|
|
if (op != Add) && (op != Remove) {
|
|
|
|
return nil, ErrParseCommand
|
2014-02-08 23:20:23 +01:00
|
|
|
}
|
2014-02-09 07:42:14 +01:00
|
|
|
|
|
|
|
for _, mode := range modeChange[1:] {
|
|
|
|
cmd.changes = append(cmd.changes, ModeChange{
|
|
|
|
mode: UserMode(mode),
|
|
|
|
op: op,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ModeCommand) String() string {
|
|
|
|
return fmt.Sprintf("MODE(nickname=%s, changes=%s)", cmd.nickname, cmd.changes)
|
2013-05-11 22:55:01 +02:00
|
|
|
}
|
|
|
|
|
2014-02-16 04:49:20 +01:00
|
|
|
type ChannelModeChange struct {
|
2014-02-09 07:06:10 +01:00
|
|
|
mode ChannelMode
|
|
|
|
op ModeOp
|
|
|
|
arg string
|
|
|
|
}
|
|
|
|
|
2014-02-17 20:46:40 +01:00
|
|
|
func (change *ChannelModeChange) String() (str string) {
|
|
|
|
if (change.op == Add) || (change.op == Remove) {
|
|
|
|
str = change.op.String()
|
|
|
|
}
|
|
|
|
str += change.mode.String()
|
|
|
|
if change.arg != "" {
|
|
|
|
str += " " + change.arg
|
|
|
|
}
|
|
|
|
return
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
|
|
|
|
2014-02-16 04:49:20 +01:00
|
|
|
type ChannelModeChanges []ChannelModeChange
|
|
|
|
|
2014-02-17 20:46:40 +01:00
|
|
|
func (changes ChannelModeChanges) String() (str string) {
|
2014-02-16 04:49:20 +01:00
|
|
|
if len(changes) == 0 {
|
2014-02-17 20:46:40 +01:00
|
|
|
return
|
2014-02-16 04:49:20 +01:00
|
|
|
}
|
|
|
|
|
2014-02-17 20:46:40 +01:00
|
|
|
str = "+"
|
2014-02-16 04:49:20 +01:00
|
|
|
if changes[0].op == Remove {
|
|
|
|
str = "-"
|
|
|
|
}
|
|
|
|
for _, change := range changes {
|
|
|
|
str += change.mode.String()
|
|
|
|
}
|
|
|
|
for _, change := range changes {
|
2014-02-17 20:46:40 +01:00
|
|
|
if change.arg == "" {
|
|
|
|
continue
|
|
|
|
}
|
2014-02-16 04:49:20 +01:00
|
|
|
str += " " + change.arg
|
|
|
|
}
|
2014-02-17 20:46:40 +01:00
|
|
|
return
|
2014-02-16 04:49:20 +01:00
|
|
|
}
|
|
|
|
|
2014-02-09 03:14:39 +01:00
|
|
|
type ChannelModeCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
channel string
|
2014-02-16 04:49:20 +01:00
|
|
|
changes ChannelModeChanges
|
2014-02-09 03:14:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewChannelModeCommand(args []string) (editableCommand, error) {
|
2014-02-09 03:14:39 +01:00
|
|
|
cmd := &ChannelModeCommand{
|
|
|
|
channel: args[0],
|
2014-02-16 04:49:20 +01:00
|
|
|
changes: make(ChannelModeChanges, 0),
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
|
|
|
args = args[1:]
|
|
|
|
|
|
|
|
for len(args) > 0 {
|
|
|
|
modeArg := args[0]
|
2014-02-09 07:42:14 +01:00
|
|
|
|
|
|
|
op := ModeOp(modeArg[0])
|
|
|
|
if (op == Add) || (op == Remove) {
|
2014-02-09 07:06:10 +01:00
|
|
|
modeArg = modeArg[1:]
|
2014-02-09 07:42:14 +01:00
|
|
|
} else {
|
|
|
|
op = List
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
2014-02-09 07:42:14 +01:00
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
skipArgs := 1
|
2014-02-09 07:42:14 +01:00
|
|
|
for _, mode := range modeArg {
|
2014-02-16 04:49:20 +01:00
|
|
|
change := ChannelModeChange{
|
2014-02-09 07:06:10 +01:00
|
|
|
mode: ChannelMode(mode),
|
|
|
|
op: op,
|
|
|
|
}
|
2014-02-16 04:49:20 +01:00
|
|
|
switch change.mode {
|
2014-02-23 00:01:11 +01:00
|
|
|
case Key, BanMask, ExceptMask, InviteMask, UserLimit,
|
2014-02-17 20:46:40 +01:00
|
|
|
ChannelOperator, ChannelCreator, Voice:
|
2014-02-09 07:06:10 +01:00
|
|
|
if len(args) > skipArgs {
|
2014-02-16 04:49:20 +01:00
|
|
|
change.arg = args[skipArgs]
|
2014-02-09 07:06:10 +01:00
|
|
|
skipArgs += 1
|
|
|
|
}
|
|
|
|
}
|
2014-02-16 04:49:20 +01:00
|
|
|
cmd.changes = append(cmd.changes, change)
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
|
|
|
args = args[skipArgs:]
|
2012-12-10 05:24:53 +01:00
|
|
|
}
|
2014-02-09 07:06:10 +01:00
|
|
|
|
2014-02-09 03:14:39 +01:00
|
|
|
return cmd, nil
|
|
|
|
}
|
2012-12-15 23:34:20 +01:00
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func (msg *ChannelModeCommand) String() string {
|
2014-02-16 04:49:20 +01:00
|
|
|
return fmt.Sprintf("MODE(channel=%s, changes=%s)", msg.channel, msg.changes)
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewModeCommand(args []string) (editableCommand, error) {
|
2014-02-09 03:14:39 +01:00
|
|
|
if len(args) == 0 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
|
|
|
|
if IsChannel(args[0]) {
|
|
|
|
return NewChannelModeCommand(args)
|
|
|
|
} else {
|
|
|
|
return NewUserModeCommand(args)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-09 02:43:59 +01:00
|
|
|
type WhoisCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
target string
|
|
|
|
masks []string
|
|
|
|
}
|
|
|
|
|
2014-02-09 03:49:52 +01:00
|
|
|
// WHOIS [ <target> ] <mask> *( "," <mask> )
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewWhoisCommand(args []string) (editableCommand, error) {
|
2014-02-09 02:43:59 +01:00
|
|
|
if len(args) < 1 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
|
|
|
|
var masks string
|
|
|
|
var target string
|
|
|
|
|
|
|
|
if len(args) > 1 {
|
|
|
|
target = args[0]
|
|
|
|
masks = args[1]
|
|
|
|
} else {
|
|
|
|
masks = args[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
return &WhoisCommand{
|
|
|
|
target: target,
|
|
|
|
masks: strings.Split(masks, ","),
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-09 03:49:52 +01:00
|
|
|
|
2014-02-09 07:06:10 +01:00
|
|
|
func (msg *WhoisCommand) String() string {
|
|
|
|
return fmt.Sprintf("WHOIS(target=%s, masks=%s)", msg.target, msg.masks)
|
|
|
|
}
|
|
|
|
|
2014-02-09 03:49:52 +01:00
|
|
|
type WhoCommand struct {
|
|
|
|
BaseCommand
|
2014-02-09 07:42:14 +01:00
|
|
|
mask Mask
|
2014-02-09 03:49:52 +01:00
|
|
|
operatorOnly bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// WHO [ <mask> [ "o" ] ]
|
2014-02-09 07:06:10 +01:00
|
|
|
func NewWhoCommand(args []string) (editableCommand, error) {
|
2014-02-09 03:49:52 +01:00
|
|
|
cmd := &WhoCommand{}
|
|
|
|
|
|
|
|
if len(args) > 0 {
|
2014-02-09 07:42:14 +01:00
|
|
|
cmd.mask = Mask(args[0])
|
2014-02-09 03:49:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (len(args) > 1) && (args[1] == "o") {
|
|
|
|
cmd.operatorOnly = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-09 07:06:10 +01:00
|
|
|
|
|
|
|
func (msg *WhoCommand) String() string {
|
2014-02-21 04:22:08 +01:00
|
|
|
return fmt.Sprintf("WHO(mask=%s, operatorOnly=%t)", msg.mask, msg.operatorOnly)
|
2014-02-09 07:06:10 +01:00
|
|
|
}
|
2014-02-09 19:07:40 +01:00
|
|
|
|
|
|
|
type OperCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
name string
|
|
|
|
password string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *OperCommand) String() string {
|
|
|
|
return fmt.Sprintf("OPER(name=%s, password=%s)", msg.name, msg.password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// OPER <name> <password>
|
|
|
|
func NewOperCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) < 2 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
|
|
|
|
return &OperCommand{
|
|
|
|
name: args[0],
|
|
|
|
password: args[1],
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-10 20:14:34 +01:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
type CapCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
args []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *CapCommand) String() string {
|
|
|
|
return fmt.Sprintf("CAP(args=%s)", msg.args)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCapCommand(args []string) (editableCommand, error) {
|
|
|
|
return &CapCommand{
|
|
|
|
args: args,
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-11 03:40:06 +01:00
|
|
|
|
|
|
|
// HAPROXY support
|
|
|
|
type ProxyCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
net string
|
|
|
|
sourceIP string
|
|
|
|
destIP string
|
|
|
|
sourcePort string
|
|
|
|
destPort string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *ProxyCommand) String() string {
|
|
|
|
return fmt.Sprintf("PROXY(sourceIP=%s, sourcePort=%s)", msg.sourceIP, msg.sourcePort)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewProxyCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) < 5 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
return &ProxyCommand{
|
|
|
|
net: args[0],
|
|
|
|
sourceIP: args[1],
|
|
|
|
destIP: args[2],
|
|
|
|
sourcePort: args[3],
|
|
|
|
destPort: args[4],
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-12 00:44:58 +01:00
|
|
|
|
|
|
|
type AwayCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
text string
|
|
|
|
away bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *AwayCommand) String() string {
|
|
|
|
return fmt.Sprintf("AWAY(%s)", msg.text)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAwayCommand(args []string) (editableCommand, error) {
|
|
|
|
cmd := &AwayCommand{}
|
|
|
|
|
|
|
|
if len(args) > 0 {
|
|
|
|
cmd.text = args[0]
|
|
|
|
cmd.away = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-12 00:58:54 +01:00
|
|
|
|
|
|
|
type IsOnCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
nicks []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *IsOnCommand) String() string {
|
|
|
|
return fmt.Sprintf("ISON(nicks=%s)", msg.nicks)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewIsOnCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) == 0 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
|
|
|
|
return &IsOnCommand{
|
|
|
|
nicks: args,
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-12 01:35:32 +01:00
|
|
|
|
|
|
|
type MOTDCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
target string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewMOTDCommand(args []string) (editableCommand, error) {
|
|
|
|
cmd := &MOTDCommand{}
|
|
|
|
if len(args) > 0 {
|
|
|
|
cmd.target = args[0]
|
|
|
|
}
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-12 02:11:59 +01:00
|
|
|
|
|
|
|
type NoticeCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
target string
|
|
|
|
message string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *NoticeCommand) String() string {
|
|
|
|
return fmt.Sprintf("NOTICE(target=%s, message=%s)", cmd.target, cmd.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNoticeCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) < 2 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
return &NoticeCommand{
|
|
|
|
target: args[0],
|
|
|
|
message: args[1],
|
|
|
|
}, nil
|
|
|
|
}
|
2014-02-17 08:29:11 +01:00
|
|
|
|
|
|
|
type KickCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
kicks map[string]string
|
|
|
|
comment string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *KickCommand) Comment() string {
|
|
|
|
if msg.comment == "" {
|
|
|
|
return msg.Source().Nick()
|
|
|
|
}
|
|
|
|
return msg.comment
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewKickCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) < 2 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
channels := strings.Split(args[0], ",")
|
|
|
|
users := strings.Split(args[1], ",")
|
|
|
|
if (len(channels) != len(users)) && (len(users) != 1) {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
cmd := &KickCommand{
|
|
|
|
kicks: make(map[string]string),
|
|
|
|
}
|
|
|
|
for index, channel := range channels {
|
|
|
|
if len(users) == 1 {
|
|
|
|
cmd.kicks[channel] = users[0]
|
|
|
|
} else {
|
|
|
|
cmd.kicks[channel] = users[index]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(args) > 2 {
|
|
|
|
cmd.comment = args[2]
|
|
|
|
}
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-17 08:51:27 +01:00
|
|
|
|
|
|
|
type ListCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
channels []string
|
|
|
|
target string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewListCommand(args []string) (editableCommand, error) {
|
|
|
|
cmd := &ListCommand{}
|
|
|
|
if len(args) > 0 {
|
|
|
|
cmd.channels = strings.Split(args[0], ",")
|
|
|
|
}
|
|
|
|
if len(args) > 1 {
|
|
|
|
cmd.target = args[1]
|
|
|
|
}
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-18 06:02:03 +01:00
|
|
|
|
|
|
|
type NamesCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
channels []string
|
|
|
|
target string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNamesCommand(args []string) (editableCommand, error) {
|
|
|
|
cmd := &NamesCommand{}
|
|
|
|
if len(args) > 0 {
|
|
|
|
cmd.channels = strings.Split(args[0], ",")
|
|
|
|
}
|
|
|
|
if len(args) > 1 {
|
|
|
|
cmd.target = args[1]
|
|
|
|
}
|
|
|
|
return cmd, nil
|
|
|
|
}
|
2014-02-23 19:04:31 +01:00
|
|
|
|
|
|
|
type DebugCommand struct {
|
|
|
|
BaseCommand
|
|
|
|
subCommand string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDebugCommand(args []string) (editableCommand, error) {
|
|
|
|
if len(args) == 0 {
|
|
|
|
return nil, NotEnoughArgsError
|
|
|
|
}
|
|
|
|
|
|
|
|
return &DebugCommand{
|
|
|
|
subCommand: strings.ToUpper(args[0]),
|
|
|
|
}, nil
|
|
|
|
}
|