mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 21:39:25 +01:00
Add MONITOR command
This commit is contained in:
parent
859d0cd607
commit
1bab81091f
@ -14,7 +14,7 @@ Improved compatibility, more features, etc.
|
|||||||
### Added
|
### Added
|
||||||
* Added integrated help (with the `/HELP` command).
|
* Added integrated help (with the `/HELP` command).
|
||||||
* Added support for IRCv3.2 [capability negotiation](http://ircv3.net/specs/core/capability-negotiation-3.2.html) including CAP values.
|
* Added support for IRCv3.2 [capability negotiation](http://ircv3.net/specs/core/capability-negotiation-3.2.html) including CAP values.
|
||||||
* Added support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html), [`invite-notify`](http://ircv3.net/specs/extensions/invite-notify-3.2.html), [`sasl`](http://ircv3.net/specs/extensions/sasl-3.2.html), and draft capability [`message-tags`](http://ircv3.net/specs/core/message-tags-3.3.html) as `draft/message-tags`.
|
* Added support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html), [`invite-notify`](http://ircv3.net/specs/extensions/invite-notify-3.2.html), [`monitor`](http://ircv3.net/specs/core/monitor-3.2.html), [`sasl`](http://ircv3.net/specs/extensions/sasl-3.2.html), and draft capability [`message-tags`](http://ircv3.net/specs/core/message-tags-3.3.html) as `draft/message-tags`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Casemapping changed from custom unicode mapping to preliminary [rfc7700](https://github.com/ircv3/ircv3-specifications/pull/272) mapping.
|
* Casemapping changed from custom unicode mapping to preliminary [rfc7700](https://github.com/ircv3/ircv3-specifications/pull/272) mapping.
|
||||||
|
@ -44,6 +44,7 @@ type Client struct {
|
|||||||
hops uint
|
hops uint
|
||||||
hostname string
|
hostname string
|
||||||
idleTimer *time.Timer
|
idleTimer *time.Timer
|
||||||
|
monitoring map[string]bool
|
||||||
nick string
|
nick string
|
||||||
nickCasefolded string
|
nickCasefolded string
|
||||||
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
||||||
@ -59,6 +60,7 @@ type Client struct {
|
|||||||
username string
|
username string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClient returns a client with all the appropriate info setup.
|
||||||
func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
|
func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
socket := NewSocket(conn)
|
socket := NewSocket(conn)
|
||||||
@ -71,6 +73,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
|
|||||||
channels: make(ChannelSet),
|
channels: make(ChannelSet),
|
||||||
ctime: now,
|
ctime: now,
|
||||||
flags: make(map[UserMode]bool),
|
flags: make(map[UserMode]bool),
|
||||||
|
monitoring: make(map[string]bool),
|
||||||
server: server,
|
server: server,
|
||||||
socket: &socket,
|
socket: &socket,
|
||||||
account: &NoAccount,
|
account: &NoAccount,
|
||||||
@ -214,6 +217,8 @@ func (client *Client) Register() {
|
|||||||
}
|
}
|
||||||
client.registered = true
|
client.registered = true
|
||||||
client.Touch()
|
client.Touch()
|
||||||
|
|
||||||
|
client.alertMonitors()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) IdleTime() time.Duration {
|
func (client *Client) IdleTime() time.Duration {
|
||||||
@ -306,7 +311,6 @@ func (client *Client) ChangeNickname(nickname string) {
|
|||||||
client.nick = nickname
|
client.nick = nickname
|
||||||
client.updateNickMask()
|
client.updateNickMask()
|
||||||
client.server.clients.Add(client)
|
client.server.clients.Add(client)
|
||||||
client.Send(nil, origNickMask, "NICK", nickname)
|
|
||||||
for friend := range client.Friends() {
|
for friend := range client.Friends() {
|
||||||
friend.Send(nil, origNickMask, "NICK", nickname)
|
friend.Send(nil, origNickMask, "NICK", nickname)
|
||||||
}
|
}
|
||||||
@ -332,6 +336,14 @@ func (client *Client) destroy() {
|
|||||||
friends := client.Friends()
|
friends := client.Friends()
|
||||||
friends.Remove(client)
|
friends.Remove(client)
|
||||||
|
|
||||||
|
// alert monitors
|
||||||
|
for _, mClient := range client.server.monitoring[client.nickCasefolded] {
|
||||||
|
mClient.Send(nil, client.server.name, RPL_MONOFFLINE, mClient.nick, client.nick)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove my monitors
|
||||||
|
client.clearMonitorList()
|
||||||
|
|
||||||
// clean up channels
|
// clean up channels
|
||||||
for channel := range client.channels {
|
for channel := range client.channels {
|
||||||
channel.Quit(client)
|
channel.Quit(client)
|
||||||
|
@ -43,6 +43,15 @@ func NewClientLookupSet() *ClientLookupSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (clients *ClientLookupSet) Has(nick string) bool {
|
||||||
|
casefoldedName, err := CasefoldName(nick)
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, exists := clients.byNick[casefoldedName]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
func (clients *ClientLookupSet) Get(nick string) *Client {
|
func (clients *ClientLookupSet) Get(nick string) *Client {
|
||||||
casefoldedName, err := CasefoldName(nick)
|
casefoldedName, err := CasefoldName(nick)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -100,6 +100,10 @@ var Commands = map[string]Command{
|
|||||||
handler: modeHandler,
|
handler: modeHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
|
"MONITOR": {
|
||||||
|
handler: monitorHandler,
|
||||||
|
minParams: 1,
|
||||||
|
},
|
||||||
"MOTD": {
|
"MOTD": {
|
||||||
handler: motdHandler,
|
handler: motdHandler,
|
||||||
minParams: 0,
|
minParams: 0,
|
||||||
|
@ -93,12 +93,13 @@ type Config struct {
|
|||||||
Operator map[string]*PassConfig
|
Operator map[string]*PassConfig
|
||||||
|
|
||||||
Limits struct {
|
Limits struct {
|
||||||
NickLen int `yaml:"nicklen"`
|
NickLen uint `yaml:"nicklen"`
|
||||||
ChannelLen int `yaml:"channellen"`
|
ChannelLen uint `yaml:"channellen"`
|
||||||
AwayLen int `yaml:"awaylen"`
|
AwayLen uint `yaml:"awaylen"`
|
||||||
KickLen int `yaml:"kicklen"`
|
KickLen uint `yaml:"kicklen"`
|
||||||
TopicLen int `yaml:"topiclen"`
|
TopicLen uint `yaml:"topiclen"`
|
||||||
WhowasEntries uint `yaml:"whowas-entries"`
|
WhowasEntries uint `yaml:"whowas-entries"`
|
||||||
|
MonitorEntries uint `yaml:"monitor-entries"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
if len(config.Server.Listen) == 0 {
|
if len(config.Server.Listen) == 0 {
|
||||||
return nil, errors.New("Server listening addresses missing")
|
return nil, errors.New("Server listening addresses missing")
|
||||||
}
|
}
|
||||||
if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.TopicLen < 1 || config.Limits.TopicLen < 1 {
|
if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.KickLen < 1 || config.Limits.TopicLen < 1 {
|
||||||
return nil, errors.New("Limits aren't setup properly, check them and make them sane")
|
return nil, errors.New("Limits aren't setup properly, check them and make them sane")
|
||||||
}
|
}
|
||||||
return config, nil
|
return config, nil
|
||||||
|
205
irc/monitor.go
Normal file
205
irc/monitor.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
||||||
|
// released under the MIT license
|
||||||
|
|
||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/DanielOaks/girc-go/ircmsg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// alertMonitors alerts everyone monitoring us that we're online.
|
||||||
|
func (client *Client) alertMonitors() {
|
||||||
|
// alert monitors
|
||||||
|
for _, mClient := range client.server.monitoring[client.nickCasefolded] {
|
||||||
|
// don't have to notify ourselves
|
||||||
|
if &mClient != client {
|
||||||
|
mClient.Send(nil, client.server.name, RPL_MONONLINE, mClient.nick, client.nickMaskString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearMonitorList clears our MONITOR list.
|
||||||
|
func (client *Client) clearMonitorList() {
|
||||||
|
for name := range client.monitoring {
|
||||||
|
// just removes current client from the list
|
||||||
|
orig := client.server.monitoring[name]
|
||||||
|
var index int
|
||||||
|
for i, cli := range orig {
|
||||||
|
if &cli == client {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.server.monitoring[name] = append(orig[:index], orig[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.monitoring = make(map[string]bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage) bool{
|
||||||
|
"-": monitorRemoveHandler,
|
||||||
|
"+": monitorAddHandler,
|
||||||
|
"c": monitorClearHandler,
|
||||||
|
"l": monitorListHandler,
|
||||||
|
"s": monitorStatusHandler,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func monitorHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
handler, exists := metadataSubcommands[strings.ToLower(msg.Params[0])]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MONITOR", msg.Params[0], "Unknown subcommand")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler(server, client, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
if len(msg.Params) < 2 {
|
||||||
|
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
targets := strings.Split(msg.Params[1], ",")
|
||||||
|
for len(targets) > 0 {
|
||||||
|
// check name length
|
||||||
|
if len(targets[0]) < 1 {
|
||||||
|
targets = targets[1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove target
|
||||||
|
casefoldedTarget, err := CasefoldName(targets[0])
|
||||||
|
if err != nil {
|
||||||
|
// skip silently I guess
|
||||||
|
targets = targets[1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if client.monitoring[casefoldedTarget] {
|
||||||
|
// just removes current client from the list
|
||||||
|
orig := server.monitoring[casefoldedTarget]
|
||||||
|
var index int
|
||||||
|
for i, cli := range orig {
|
||||||
|
if &cli == client {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.monitoring[casefoldedTarget] = append(orig[:index], orig[index+1:]...)
|
||||||
|
|
||||||
|
delete(client.monitoring, casefoldedTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove first element of targets list
|
||||||
|
targets = targets[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
if len(msg.Params) < 2 {
|
||||||
|
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var online []string
|
||||||
|
var offline []string
|
||||||
|
|
||||||
|
targets := strings.Split(msg.Params[1], ",")
|
||||||
|
for len(targets) > 0 {
|
||||||
|
// check name length
|
||||||
|
if len(targets[0]) < 1 {
|
||||||
|
targets = targets[1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the monitor list length
|
||||||
|
if len(client.monitoring) >= server.limits.MonitorEntries {
|
||||||
|
client.Send(nil, server.name, ERR_MONLISTFULL, client.nick, strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// add target
|
||||||
|
casefoldedTarget, err := CasefoldName(targets[0])
|
||||||
|
if err != nil {
|
||||||
|
// skip silently I guess
|
||||||
|
targets = targets[1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !client.monitoring[casefoldedTarget] {
|
||||||
|
client.monitoring[casefoldedTarget] = true
|
||||||
|
|
||||||
|
orig := server.monitoring[casefoldedTarget]
|
||||||
|
server.monitoring[casefoldedTarget] = append(orig, *client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to online / offline lists
|
||||||
|
target := server.clients.Get(casefoldedTarget)
|
||||||
|
if target == nil {
|
||||||
|
offline = append(offline, targets[0])
|
||||||
|
} else {
|
||||||
|
online = append(online, target.nickMaskString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove first element of targets list
|
||||||
|
targets = targets[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(online) > 0 {
|
||||||
|
client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ","))
|
||||||
|
}
|
||||||
|
if len(offline) > 0 {
|
||||||
|
client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
client.clearMonitorList()
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
var monitorList []string
|
||||||
|
for name := range client.monitoring {
|
||||||
|
monitorList = append(monitorList, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Send(nil, server.name, RPL_MONLIST, client.nick, strings.Join(monitorList, ","))
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
var online []string
|
||||||
|
var offline []string
|
||||||
|
|
||||||
|
for name := range client.monitoring {
|
||||||
|
target := server.clients.Get(name)
|
||||||
|
if target == nil {
|
||||||
|
offline = append(offline, name)
|
||||||
|
} else {
|
||||||
|
online = append(online, target.nickMaskString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(online) > 0 {
|
||||||
|
client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ","))
|
||||||
|
}
|
||||||
|
if len(offline) > 0 {
|
||||||
|
client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -43,6 +43,7 @@ func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|||||||
|
|
||||||
if client.registered {
|
if client.registered {
|
||||||
client.ChangeNickname(nicknameRaw)
|
client.ChangeNickname(nicknameRaw)
|
||||||
|
client.alertMonitors()
|
||||||
} else {
|
} else {
|
||||||
client.SetNickname(nicknameRaw)
|
client.SetNickname(nicknameRaw)
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,11 @@ const (
|
|||||||
RPL_HELPSTART = "704"
|
RPL_HELPSTART = "704"
|
||||||
RPL_HELPTXT = "705"
|
RPL_HELPTXT = "705"
|
||||||
RPL_ENDOFHELP = "706"
|
RPL_ENDOFHELP = "706"
|
||||||
|
RPL_MONONLINE = "730"
|
||||||
|
RPL_MONOFFLINE = "731"
|
||||||
|
RPL_MONLIST = "732"
|
||||||
|
RPL_ENDOFMONLIST = "733"
|
||||||
|
ERR_MONLISTFULL = "734"
|
||||||
RPL_LOGGEDIN = "900"
|
RPL_LOGGEDIN = "900"
|
||||||
RPL_LOGGEDOUT = "901"
|
RPL_LOGGEDOUT = "901"
|
||||||
ERR_NICKLOCKED = "902"
|
ERR_NICKLOCKED = "902"
|
||||||
|
@ -26,11 +26,12 @@ import (
|
|||||||
|
|
||||||
// Limits holds the maximum limits for various things such as topic lengths
|
// Limits holds the maximum limits for various things such as topic lengths
|
||||||
type Limits struct {
|
type Limits struct {
|
||||||
AwayLen int
|
AwayLen int
|
||||||
ChannelLen int
|
ChannelLen int
|
||||||
KickLen int
|
KickLen int
|
||||||
NickLen int
|
MonitorEntries int
|
||||||
TopicLen int
|
NickLen int
|
||||||
|
TopicLen int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
@ -42,6 +43,7 @@ type Server struct {
|
|||||||
store buntdb.DB
|
store buntdb.DB
|
||||||
idle chan *Client
|
idle chan *Client
|
||||||
limits Limits
|
limits Limits
|
||||||
|
monitoring map[string][]Client
|
||||||
motdLines []string
|
motdLines []string
|
||||||
name string
|
name string
|
||||||
nameCasefolded string
|
nameCasefolded string
|
||||||
@ -85,12 +87,14 @@ func NewServer(config *Config) *Server {
|
|||||||
ctime: time.Now(),
|
ctime: time.Now(),
|
||||||
idle: make(chan *Client),
|
idle: make(chan *Client),
|
||||||
limits: Limits{
|
limits: Limits{
|
||||||
AwayLen: config.Limits.AwayLen,
|
AwayLen: int(config.Limits.AwayLen),
|
||||||
ChannelLen: config.Limits.ChannelLen,
|
ChannelLen: int(config.Limits.ChannelLen),
|
||||||
KickLen: config.Limits.KickLen,
|
KickLen: int(config.Limits.KickLen),
|
||||||
NickLen: config.Limits.NickLen,
|
MonitorEntries: int(config.Limits.MonitorEntries),
|
||||||
TopicLen: config.Limits.TopicLen,
|
NickLen: int(config.Limits.NickLen),
|
||||||
|
TopicLen: int(config.Limits.TopicLen),
|
||||||
},
|
},
|
||||||
|
monitoring: make(map[string][]Client),
|
||||||
name: config.Server.Name,
|
name: config.Server.Name,
|
||||||
nameCasefolded: casefoldedName,
|
nameCasefolded: casefoldedName,
|
||||||
newConns: make(chan clientConn),
|
newConns: make(chan clientConn),
|
||||||
@ -172,15 +176,16 @@ func NewServer(config *Config) *Server {
|
|||||||
server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
|
server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
|
||||||
server.isupport.Add("CASEMAPPING", "rfc7700")
|
server.isupport.Add("CASEMAPPING", "rfc7700")
|
||||||
server.isupport.Add("CHANMODES", strings.Join([]string{ChannelModes{BanMask, ExceptMask, InviteMask}.String(), "", ChannelModes{UserLimit, Key}.String(), ChannelModes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret}.String()}, ","))
|
server.isupport.Add("CHANMODES", strings.Join([]string{ChannelModes{BanMask, ExceptMask, InviteMask}.String(), "", ChannelModes{UserLimit, Key}.String(), ChannelModes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret}.String()}, ","))
|
||||||
server.isupport.Add("CHANNELLEN", strconv.Itoa(config.Limits.ChannelLen))
|
server.isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
|
||||||
server.isupport.Add("CHANTYPES", "#")
|
server.isupport.Add("CHANTYPES", "#")
|
||||||
server.isupport.Add("EXCEPTS", "")
|
server.isupport.Add("EXCEPTS", "")
|
||||||
server.isupport.Add("INVEX", "")
|
server.isupport.Add("INVEX", "")
|
||||||
server.isupport.Add("KICKLEN", strconv.Itoa(server.limits.KickLen))
|
server.isupport.Add("KICKLEN", strconv.Itoa(server.limits.KickLen))
|
||||||
// server.isupport.Add("MAXLIST", "") //TODO(dan): Support max list length?
|
// server.isupport.Add("MAXLIST", "") //TODO(dan): Support max list length?
|
||||||
// server.isupport.Add("MODES", "") //TODO(dan): Support max modes?
|
// server.isupport.Add("MODES", "") //TODO(dan): Support max modes?
|
||||||
|
server.isupport.Add("MONITOR", strconv.Itoa(server.limits.MonitorEntries))
|
||||||
server.isupport.Add("NETWORK", config.Network.Name)
|
server.isupport.Add("NETWORK", config.Network.Name)
|
||||||
server.isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen))
|
server.isupport.Add("NICKLEN", strconv.Itoa(server.limits.NickLen))
|
||||||
server.isupport.Add("PREFIX", "(qaohv)~&@%+")
|
server.isupport.Add("PREFIX", "(qaohv)~&@%+")
|
||||||
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Support STATUSMSG
|
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Support STATUSMSG
|
||||||
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
||||||
|
@ -86,5 +86,8 @@ limits:
|
|||||||
# topiclen is the maximum length of a channel topic
|
# topiclen is the maximum length of a channel topic
|
||||||
topiclen: 390
|
topiclen: 390
|
||||||
|
|
||||||
|
# maximum number of monitor entries a client can have
|
||||||
|
monitor-entries: 100
|
||||||
|
|
||||||
# whowas entries to store
|
# whowas entries to store
|
||||||
whowas-entries: 100
|
whowas-entries: 100
|
||||||
|
Loading…
Reference in New Issue
Block a user