goirc/state/nick.go

181 lines
4.4 KiB
Go
Raw Normal View History

package state
import (
"github.com/fluffle/goirc/logging"
"reflect"
"sort"
)
// A struct representing an IRC nick
type Nick struct {
Nick, Ident, Host, Name string
Modes *NickMode
2011-11-13 13:32:53 +00:00
lookup map[string]*Channel
chans map[*Channel]*ChanPrivs
}
// A struct representing the modes of an IRC Nick (User Modes)
// (again, only the ones we care about)
//
// This is only really useful for me, as we can't see other people's modes
// without IRC operator privileges (and even then only on some IRCd's).
type NickMode struct {
2013-01-06 18:52:11 +00:00
// MODE +B, +i, +o, +w, +x, +z
Bot, Invisible, Oper, WallOps, HiddenHost, SSL bool
}
// Map *irc.NickMode fields to IRC mode characters and vice versa
var StringToNickMode = map[string]string{}
var NickModeToString = map[string]string{
2013-01-06 18:52:11 +00:00
"Bot": "B",
"Invisible": "i",
"Oper": "o",
"WallOps": "w",
"HiddenHost": "x",
"SSL": "z",
}
func init() {
for k, v := range NickModeToString {
StringToNickMode[v] = k
}
}
/******************************************************************************\
* Nick methods for state management
\******************************************************************************/
func NewNick(n string) *Nick {
return &Nick{
2011-11-13 13:32:53 +00:00
Nick: n,
Modes: new(NickMode),
chans: make(map[*Channel]*ChanPrivs),
2011-10-19 23:10:33 +00:00
lookup: make(map[string]*Channel),
}
}
// Returns true if the Nick is associated with the Channel.
func (nk *Nick) IsOn(ch *Channel) (*ChanPrivs, bool) {
cp, ok := nk.chans[ch]
return cp, ok
}
func (nk *Nick) IsOnStr(c string) (*Channel, bool) {
ch, ok := nk.lookup[c]
return ch, ok
}
2011-10-19 23:10:33 +00:00
// Associates a Channel with a Nick.
func (nk *Nick) addChannel(ch *Channel, cp *ChanPrivs) {
if _, ok := nk.chans[ch]; !ok {
nk.chans[ch] = cp
nk.lookup[ch.Name] = ch
} else {
logging.Warn("Nick.addChannel(): %s already on %s.", nk.Nick, ch.Name)
}
}
2011-10-19 23:10:33 +00:00
// Disassociates a Channel from a Nick.
func (nk *Nick) delChannel(ch *Channel) {
if _, ok := nk.chans[ch]; ok {
2011-11-13 13:32:53 +00:00
delete(nk.chans, ch)
delete(nk.lookup, ch.Name)
} else {
logging.Warn("Nick.delChannel(): %s not on %s.", nk.Nick, ch.Name)
}
}
// Parse mode strings for a Nick.
2011-10-19 23:10:33 +00:00
func (nk *Nick) ParseModes(modes string) {
var modeop bool // true => add mode, false => remove mode
for i := 0; i < len(modes); i++ {
switch m := modes[i]; m {
case '+':
modeop = true
case '-':
modeop = false
2013-01-06 18:52:11 +00:00
case 'B':
nk.Modes.Bot = modeop
case 'i':
2011-10-19 23:10:33 +00:00
nk.Modes.Invisible = modeop
case 'o':
2011-10-19 23:10:33 +00:00
nk.Modes.Oper = modeop
case 'w':
2011-10-19 23:10:33 +00:00
nk.Modes.WallOps = modeop
case 'x':
2011-10-19 23:10:33 +00:00
nk.Modes.HiddenHost = modeop
case 'z':
2011-10-19 23:10:33 +00:00
nk.Modes.SSL = modeop
default:
logging.Info("Nick.ParseModes(): unknown mode char %c", m)
}
}
}
type byName []*Channel
func (b byName) Len() int { return len(b) }
func (b byName) Less(i, j int) bool { return b[i].Name < b[j].Name }
func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// Channels returns a list of *Channel the nick is on, sorted by name.
func (nk *Nick) Channels() []*Channel {
channels := make([]*Channel, 0, len(nk.lookup))
for _, channel := range nk.lookup {
channels = append(channels, channel)
}
sort.Sort(byName(channels))
return channels
}
// ChannelsStr returns a list of channel strings the nick is on, sorted by name.
func (nk *Nick) ChannelsStr() []string {
var names []string
for _, channel := range nk.Channels() {
names = append(names, channel.Name)
}
return names
}
// Returns a string representing the nick. Looks like:
// Nick: <nick name> e.g. CowMaster
// Hostmask: <ident@host> e.g. moo@cows.org
// Real Name: <real name> e.g. Steve "CowMaster" Bush
// Modes: <nick modes> e.g. +z
// Channels:
// <channel>: <privs> e.g. #moo: +o
// ...
2011-10-19 23:10:33 +00:00
func (nk *Nick) String() string {
str := "Nick: " + nk.Nick + "\n\t"
str += "Hostmask: " + nk.Ident + "@" + nk.Host + "\n\t"
str += "Real Name: " + nk.Name + "\n\t"
str += "Modes: " + nk.Modes.String() + "\n\t"
str += "Channels: \n"
2011-10-19 23:10:33 +00:00
for ch, cp := range nk.chans {
str += "\t\t" + ch.Name + ": " + cp.String() + "\n"
}
return str
}
// Returns a string representing the nick modes. Looks like:
// +iwx
func (nm *NickMode) String() string {
str := "+"
v := reflect.Indirect(reflect.ValueOf(nm))
t := v.Type()
for i := 0; i < v.NumField(); i++ {
switch f := v.Field(i); f.Kind() {
// only bools here at the mo!
case reflect.Bool:
if f.Bool() {
str += NickModeToString[t.Field(i).Name]
}
}
}
if str == "+" {
str = "No modes set"
}
return str
}