3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-10 22:19:31 +01:00
ergo/src/irc/commands.go

368 lines
6.3 KiB
Go
Raw Normal View History

package irc
2012-12-09 21:51:50 +01:00
import (
"errors"
"fmt"
"regexp"
"strconv"
"strings"
)
2012-04-18 05:24:26 +02:00
type Message interface {
Handle(s *Server, c *Client)
}
2012-12-09 21:51:50 +01:00
var (
ErrNotEnoughArgs = errors.New("not enough arguments")
ErrUModeUnknownFlag = errors.New("unknown umode flag")
2012-12-09 22:47:02 +01:00
parseCommandFuncs = map[string]ParseFunc{
"INVITE": NewInviteMessage,
"JOIN": NewJoinMessage,
"MODE": NewModeMessage,
"NICK": NewNickMessage,
"PART": NewPartMessage,
"PING": NewPingMessage,
"PONG": NewPongMessage,
"PRIVMSG": NewPrivMsgMessage,
"QUIT": NewQuitMessage,
"TOPIC": NewTopicMessage,
"USER": NewUserMessage,
}
2012-12-09 21:51:50 +01:00
)
// unknown
type UnknownMessage struct {
command string
}
2012-12-09 21:51:50 +01:00
// NB: no constructor, created on demand in parser for invalid messages.
func (m *UnknownMessage) Handle(s *Server, c *Client) {
c.send <- ErrUnknownCommand(s, m.command)
}
// PING
type PingMessage struct {
server string
server2 string
}
2012-12-09 21:51:50 +01:00
func NewPingMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
}
msg := &PingMessage{server: args[0]}
if len(args) > 1 {
msg.server2 = args[1]
}
return msg, nil
}
func (m *PingMessage) Handle(s *Server, c *Client) {
c.send <- RplPong(s)
}
// PONG
type PongMessage struct {
server1 string
server2 string
}
2012-12-09 21:51:50 +01:00
func NewPongMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
}
message := &PongMessage{server1: args[0]}
if len(args) > 1 {
message.server2 = args[1]
}
return message, nil
}
func (m *PongMessage) Handle(s *Server, c *Client) {
2012-12-09 21:51:50 +01:00
// no-op
}
// NICK
type NickMessage struct {
nickname string
}
2012-12-09 21:51:50 +01:00
func NewNickMessage(args []string) (Message, error) {
if len(args) != 1 {
return nil, ErrNotEnoughArgs
}
return &NickMessage{args[0]}, nil
}
func (m *NickMessage) Handle(s *Server, c *Client) {
s.ChangeNick(c, m.nickname)
}
// USER
type UserMessage struct {
user string
mode uint8
unused string
realname string
}
2012-12-09 21:51:50 +01:00
func NewUserMessage(args []string) (Message, error) {
if len(args) != 4 {
return nil, ErrNotEnoughArgs
}
msg := &UserMessage{
user: args[0],
unused: args[2],
realname: args[3],
}
mode, err := strconv.ParseUint(args[1], 10, 8)
if err == nil {
msg.mode = uint8(mode)
}
return msg, nil
}
func (m *UserMessage) Handle(s *Server, c *Client) {
2012-12-09 21:51:50 +01:00
s.UserLogin(c, m.user, m.realname)
}
// QUIT
type QuitMessage struct {
message string
}
2012-12-09 21:51:50 +01:00
func NewQuitMessage(args []string) (Message, error) {
msg := &QuitMessage{}
if len(args) > 0 {
msg.message = args[0]
}
return msg, nil
}
func (m *QuitMessage) Handle(s *Server, c *Client) {
s.Quit(c, m.message)
}
// MODE
type ModeMessage struct {
nickname string
modes []string
}
2012-12-09 21:51:50 +01:00
var MODE_RE = regexp.MustCompile("^[-+][a-zA-Z]+$")
func NewModeMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
}
msg := &ModeMessage{
nickname: args[0],
}
for _, arg := range args[1:] {
if !MODE_RE.MatchString(arg) {
return nil, ErrUModeUnknownFlag
}
prefix := arg[0]
for _, c := range arg[1:] {
mode := fmt.Sprintf("%c%c", prefix, c)
msg.modes = append(msg.modes, mode)
}
}
return msg, nil
}
2012-04-18 05:24:26 +02:00
func (m *ModeMessage) Handle(s *Server, c *Client) {
if m.nickname != c.nick {
c.send <- ErrUsersDontMatch(s)
2012-04-18 05:24:26 +02:00
return
}
s.ChangeUserMode(c, m.modes)
}
// JOIN
type JoinMessage struct {
channels []string
keys []string
zero bool
}
2012-12-09 21:51:50 +01:00
func NewJoinMessage(args []string) (Message, error) {
msg := &JoinMessage{}
if len(args) > 0 {
if args[0] == "0" {
msg.zero = true
} else {
msg.channels = strings.Split(args[0], ",")
}
if len(args) > 1 {
msg.keys = strings.Split(args[1], ",")
}
}
return msg, nil
}
func (m *JoinMessage) Handle(s *Server, c *Client) {
if m.zero {
for channel := range c.channels {
channel.Part(c, "")
}
} else {
for i, name := range m.channels {
key := ""
if len(m.keys) > i {
key = m.keys[i]
}
s.GetOrMakeChannel(name).Join(c, key)
}
}
}
// PART
type PartMessage struct {
channels []string
message string
}
2012-12-09 21:51:50 +01:00
func NewPartMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
}
msg := &PartMessage{channels: strings.Split(args[0], ",")}
if len(args) > 1 {
msg.message = args[1]
}
return msg, nil
}
func (m *PartMessage) Handle(s *Server, c *Client) {
for _, chname := range m.channels {
channel := s.channels[chname]
if channel == nil {
c.send <- ErrNoSuchChannel(s, chname)
continue
2012-04-18 05:24:26 +02:00
}
channel.Part(c, m.message)
2012-04-18 05:24:26 +02:00
}
}
// PRIVMSG
type PrivMsgMessage struct {
target string
message string
}
2012-12-09 21:51:50 +01:00
func NewPrivMsgMessage(args []string) (Message, error) {
if len(args) < 2 {
return nil, ErrNotEnoughArgs
}
return &PrivMsgMessage{
target: args[0],
message: args[1],
}, nil
}
func (m *PrivMsgMessage) TargetIsChannel() bool {
switch m.target[0] {
case '&', '#', '+', '!':
return true
}
return false
}
func (m *PrivMsgMessage) Handle(s *Server, c *Client) {
if m.TargetIsChannel() {
channel := s.channels[m.target]
if channel != nil {
channel.PrivMsg(c, m.message)
} else {
c.send <- ErrNoSuchNick(s, m.target)
}
} else {
client := s.nicks[m.target]
if client != nil {
client.send <- RplPrivMsg(client, m.message)
} else {
c.send <- ErrNoSuchNick(s, m.target)
}
}
}
// TOPIC
type TopicMessage struct {
channel string
topic string
}
2012-12-09 21:51:50 +01:00
func NewTopicMessage(args []string) (Message, error) {
if len(args) < 1 {
return nil, ErrNotEnoughArgs
}
msg := &TopicMessage{channel: args[0]}
if len(args) > 1 {
msg.topic = args[1]
}
return msg, nil
}
func (m *TopicMessage) Handle(s *Server, c *Client) {
channel := s.channels[m.channel]
if channel == nil {
c.send <- ErrNoSuchChannel(s, m.channel)
return
}
if m.topic == "" {
channel.GetTopic(c)
} else {
channel.ChangeTopic(c, m.topic)
}
}
2012-12-09 22:47:02 +01:00
// INVITE <nickname> <channel>
type InviteMessage struct {
nickname string
channel string
}
func NewInviteMessage(args []string) (Message, error) {
if len(args) < 2 {
return nil, ErrNotEnoughArgs
}
return &InviteMessage{
nickname: args[0],
channel: args[1],
}, nil
}
func (m *InviteMessage) Handle(s *Server, c *Client) {
channel := s.channels[m.channel]
if channel == nil {
c.send <- ErrNoSuchNick(s, m.channel)
return
}
invitee := s.nicks[m.nickname]
if invitee == nil {
c.send <- ErrNoSuchNick(s, m.nickname)
return
}
channel.Invite(c, invitee)
}