move modes code to its own file; fix SQL (un)marshalling

This commit is contained in:
Jeremy Latt 2014-03-13 13:18:40 -07:00
parent 4ed0d78d87
commit d85e6681d9
7 changed files with 173 additions and 136 deletions

View File

@ -444,8 +444,8 @@ func (channel *Channel) Persist() (err error) {
(name, flags, key, topic, user_limit, ban_list, except_list,
invite_list)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
channel.name, channel.flags.String(), channel.key, channel.topic,
channel.userLimit, channel.lists[BanMask].String(),
channel.name.String(), channel.flags.String(), channel.key.String(),
channel.topic.String(), channel.userLimit, channel.lists[BanMask].String(),
channel.lists[ExceptMask].String(), channel.lists[InviteMask].String())
} else {
_, err = channel.server.db.Exec(`

View File

@ -153,7 +153,7 @@ func NewClientDB() *ClientDB {
func (db *ClientDB) Add(client *Client) {
_, err := db.db.Exec(`INSERT INTO client (nickname, userhost) VALUES (?, ?)`,
client.Nick(), client.UserHost())
client.Nick().String(), client.UserHost().String())
if err != nil {
Log.error.Println("ClientDB.Add:", err)
}
@ -161,7 +161,7 @@ func (db *ClientDB) Add(client *Client) {
func (db *ClientDB) Remove(client *Client) {
_, err := db.db.Exec(`DELETE FROM client WHERE nickname = ?`,
client.Nick())
client.Nick().String())
if err != nil {
Log.error.Println("ClientDB.Remove:", err)
}

View File

@ -1,14 +1,5 @@
package irc
import (
"errors"
)
var (
// errors
ErrAlreadyDestroyed = errors.New("already destroyed")
)
const (
SEM_VER = "ergonomadic-1.3.1"
CRLF = "\r\n"
@ -184,35 +175,4 @@ const (
ERR_NOOPERHOST NumericCode = 491
ERR_UMODEUNKNOWNFLAG NumericCode = 501
ERR_USERSDONTMATCH NumericCode = 502
Add ModeOp = '+'
List ModeOp = '='
Remove ModeOp = '-'
Away UserMode = 'a'
Invisible UserMode = 'i'
LocalOperator UserMode = 'O'
Operator UserMode = 'o'
Restricted UserMode = 'r'
ServerNotice UserMode = 's' // deprecated
WallOps UserMode = 'w'
Anonymous ChannelMode = 'a' // flag
BanMask ChannelMode = 'b' // arg
ChannelCreator ChannelMode = 'O' // flag
ChannelOperator ChannelMode = 'o' // arg
ExceptMask ChannelMode = 'e' // arg
InviteMask ChannelMode = 'I' // arg
InviteOnly ChannelMode = 'i' // flag
Key ChannelMode = 'k' // flag arg
Moderated ChannelMode = 'm' // flag
NoOutside ChannelMode = 'n' // flag
OpOnlyTopic ChannelMode = 't' // flag
Persistent ChannelMode = 'P' // flag
Private ChannelMode = 'p' // flag
Quiet ChannelMode = 'q' // flag
ReOp ChannelMode = 'r' // flag
Secret ChannelMode = 's' // flag, deprecated
UserLimit ChannelMode = 'l' // flag arg
Voice ChannelMode = 'v' // arg
)

162
irc/modes.go Normal file
View File

@ -0,0 +1,162 @@
package irc
import (
"strings"
)
// user mode flags
type UserMode rune
func (mode UserMode) String() string {
return string(mode)
}
type UserModes []UserMode
func (modes UserModes) String() string {
strs := make([]string, len(modes))
for index, mode := range modes {
strs[index] = mode.String()
}
return strings.Join(strs, "")
}
// channel mode flags
type ChannelMode rune
func (mode ChannelMode) String() string {
return string(mode)
}
type ChannelModes []ChannelMode
func (modes ChannelModes) String() string {
strs := make([]string, len(modes))
for index, mode := range modes {
strs[index] = mode.String()
}
return strings.Join(strs, "")
}
type ModeOp rune
func (op ModeOp) String() string {
return string(op)
}
const (
Add ModeOp = '+'
List ModeOp = '='
Remove ModeOp = '-'
)
const (
Away UserMode = 'a'
Invisible UserMode = 'i'
LocalOperator UserMode = 'O'
Operator UserMode = 'o'
Restricted UserMode = 'r'
ServerNotice UserMode = 's' // deprecated
WallOps UserMode = 'w'
)
var (
SupportedUserModes = UserModes{
Away, Invisible, Operator,
}
)
const (
Anonymous ChannelMode = 'a' // flag
BanMask ChannelMode = 'b' // arg
ChannelCreator ChannelMode = 'O' // flag
ChannelOperator ChannelMode = 'o' // arg
ExceptMask ChannelMode = 'e' // arg
InviteMask ChannelMode = 'I' // arg
InviteOnly ChannelMode = 'i' // flag
Key ChannelMode = 'k' // flag arg
Moderated ChannelMode = 'm' // flag
NoOutside ChannelMode = 'n' // flag
OpOnlyTopic ChannelMode = 't' // flag
Persistent ChannelMode = 'P' // flag
Private ChannelMode = 'p' // flag
Quiet ChannelMode = 'q' // flag
ReOp ChannelMode = 'r' // flag
Secret ChannelMode = 's' // flag, deprecated
UserLimit ChannelMode = 'l' // flag arg
Voice ChannelMode = 'v' // arg
)
var (
SupportedChannelModes = ChannelModes{
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
OpOnlyTopic, Persistent, Private, UserLimit,
}
)
//
// commands
//
func (m *ModeCommand) HandleServer(s *Server) {
client := m.Client()
target := s.clients.Get(m.nickname)
if target == nil {
client.ErrNoSuchNick(m.nickname)
return
}
if client != target && !client.flags[Operator] {
client.ErrUsersDontMatch()
return
}
changes := make(ModeChanges, 0, len(m.changes))
for _, change := range m.changes {
switch change.mode {
case Invisible, ServerNotice, WallOps:
switch change.op {
case Add:
if target.flags[change.mode] {
continue
}
target.flags[change.mode] = true
changes = append(changes, change)
case Remove:
if !target.flags[change.mode] {
continue
}
delete(target.flags, change.mode)
changes = append(changes, change)
}
case Operator, LocalOperator:
if change.op == Remove {
if !target.flags[change.mode] {
continue
}
delete(target.flags, change.mode)
changes = append(changes, change)
}
}
}
// Who should get these replies?
if len(changes) > 0 {
client.Reply(RplMode(client, target, changes))
}
}
func (msg *ChannelModeCommand) HandleServer(server *Server) {
client := msg.Client()
channel := server.channels.Get(msg.channel)
if channel == nil {
client.ErrNoSuchChannel(msg.channel)
return
}
channel.Mode(client, msg.changes)
}

View File

@ -181,7 +181,8 @@ func (target *Client) RplCreated() {
func (target *Client) RplMyInfo() {
target.NumericReply(RPL_MYINFO,
"%s %s aiOorsw abeIikmntpqrsl", target.server.name, SEM_VER)
"%s %s %s %s",
target.server.name, SEM_VER, SupportedUserModes, SupportedChannelModes)
}
func (target *Client) RplUModeIs(client *Client) {

View File

@ -94,9 +94,7 @@ func (server *Server) loadChannels() {
log.Fatal("error loading channels: ", err)
}
for rows.Next() {
var name Name
var flags string
var key, topic Text
var name, flags, key, topic string
var userLimit uint64
var banList, exceptList, inviteList string
err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
@ -106,12 +104,12 @@ func (server *Server) loadChannels() {
continue
}
channel := NewChannel(server, name)
channel := NewChannel(server, NewName(name))
for _, flag := range flags {
channel.flags[ChannelMode(flag)] = true
}
channel.key = key
channel.topic = topic
channel.key = NewText(key)
channel.topic = NewText(topic)
channel.userLimit = userLimit
loadChannelList(channel, banList, BanMask)
loadChannelList(channel, exceptList, ExceptMask)
@ -339,7 +337,7 @@ func (msg *RFC2812UserCommand) HandleRegServer(server *Server) {
}
flags := msg.Flags()
if len(flags) > 0 {
for _, mode := range msg.Flags() {
for _, mode := range flags {
client.flags[mode] = true
}
client.RplUModeIs(client)
@ -491,58 +489,6 @@ func (msg *PrivMsgCommand) HandleServer(server *Server) {
}
}
func (m *ModeCommand) HandleServer(s *Server) {
client := m.Client()
target := s.clients.Get(m.nickname)
if target == nil {
client.ErrNoSuchNick(m.nickname)
return
}
if client != target && !client.flags[Operator] {
client.ErrUsersDontMatch()
return
}
changes := make(ModeChanges, 0, len(m.changes))
for _, change := range m.changes {
switch change.mode {
case Invisible, ServerNotice, WallOps:
switch change.op {
case Add:
if target.flags[change.mode] {
continue
}
target.flags[change.mode] = true
changes = append(changes, change)
case Remove:
if !target.flags[change.mode] {
continue
}
delete(target.flags, change.mode)
changes = append(changes, change)
}
case Operator, LocalOperator:
if change.op == Remove {
if !target.flags[change.mode] {
continue
}
delete(target.flags, change.mode)
changes = append(changes, change)
}
}
}
// Who should get these replies?
if len(changes) > 0 {
client.Reply(RplMode(client, target, changes))
}
}
func (client *Client) WhoisChannelsNames() []string {
chstrs := make([]string, len(client.channels))
index := 0
@ -579,17 +525,6 @@ func (m *WhoisCommand) HandleServer(server *Server) {
}
}
func (msg *ChannelModeCommand) HandleServer(server *Server) {
client := msg.Client()
channel := server.channels.Get(msg.channel)
if channel == nil {
client.ErrNoSuchChannel(msg.channel)
return
}
channel.Mode(client, msg.changes)
}
func whoChannel(client *Client, channel *Channel, friends ClientSet) {
for member := range channel.members {
if !client.flags[Invisible] || friends[client] {

View File

@ -9,27 +9,6 @@ import (
// simple types
//
// add, remove, list modes
type ModeOp rune
func (op ModeOp) String() string {
return string(op)
}
// user mode flags
type UserMode rune
func (mode UserMode) String() string {
return string(mode)
}
// channel mode flags
type ChannelMode rune
func (mode ChannelMode) String() string {
return string(mode)
}
type ChannelNameMap map[Name]*Channel
func (channels ChannelNameMap) Get(name Name) *Channel {