mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
Merge pull request #479 from slingamn/compat.4
add client compatibility switches
This commit is contained in:
commit
585a6557a4
@ -5,7 +5,6 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -483,7 +482,7 @@ func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount str
|
|||||||
} else if callbackNamespace == "mailto" {
|
} else if callbackNamespace == "mailto" {
|
||||||
return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
|
return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
|
||||||
} else {
|
} else {
|
||||||
return "", errors.New(fmt.Sprintf("Callback not implemented: %s", callbackNamespace))
|
return "", fmt.Errorf("Callback not implemented: %s", callbackNamespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,7 +1264,6 @@ func (am *AccountManager) Logout(client *Client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
am.accountToClients[casefoldedAccount] = remainingClients
|
am.accountToClients[casefoldedAccount] = remainingClients
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1094,34 +1094,6 @@ func (channel *Channel) ShowMaskList(client *Client, mode modes.Mode, rb *Respon
|
|||||||
rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
|
rb.Add(nil, client.server.name, rplendoflist, nick, channel.name, client.t("End of list"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) applyModeMask(client *Client, mode modes.Mode, op modes.ModeOp, mask string, rb *ResponseBuffer) bool {
|
|
||||||
list := channel.lists[mode]
|
|
||||||
if list == nil {
|
|
||||||
// This should never happen, but better safe than panicky.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op == modes.List) || (mask == "") {
|
|
||||||
channel.ShowMaskList(client, mode, rb)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !channel.ClientIsAtLeast(client, modes.ChannelOperator) {
|
|
||||||
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You're not a channel operator"))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == modes.Add {
|
|
||||||
return list.Add(mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == modes.Remove {
|
|
||||||
return list.Remove(mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quit removes the given client from the channel
|
// Quit removes the given client from the channel
|
||||||
func (channel *Channel) Quit(client *Client) {
|
func (channel *Channel) Quit(client *Client) {
|
||||||
channelEmpty := func() bool {
|
channelEmpty := func() bool {
|
||||||
|
@ -557,14 +557,12 @@ func (client *Client) tryResume() (success bool) {
|
|||||||
func (client *Client) tryResumeChannels() {
|
func (client *Client) tryResumeChannels() {
|
||||||
details := client.resumeDetails
|
details := client.resumeDetails
|
||||||
|
|
||||||
channels := make([]*Channel, len(details.Channels))
|
|
||||||
for _, name := range details.Channels {
|
for _, name := range details.Channels {
|
||||||
channel := client.server.channels.Get(name)
|
channel := client.server.channels.Get(name)
|
||||||
if channel == nil {
|
if channel == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
channel.Resume(client, details.OldClient, details.Timestamp)
|
channel.Resume(client, details.OldClient, details.Timestamp)
|
||||||
channels = append(channels, channel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// replay direct PRIVSMG history
|
// replay direct PRIVSMG history
|
||||||
@ -868,7 +866,8 @@ func (client *Client) LoggedIntoAccount() bool {
|
|||||||
func (client *Client) RplISupport(rb *ResponseBuffer) {
|
func (client *Client) RplISupport(rb *ResponseBuffer) {
|
||||||
translatedISupport := client.t("are supported by this server")
|
translatedISupport := client.t("are supported by this server")
|
||||||
nick := client.Nick()
|
nick := client.Nick()
|
||||||
for _, cachedTokenLine := range client.server.ISupport().CachedReply {
|
config := client.server.Config()
|
||||||
|
for _, cachedTokenLine := range config.Server.isupport.CachedReply {
|
||||||
length := len(cachedTokenLine) + 2
|
length := len(cachedTokenLine) + 2
|
||||||
tokenline := make([]string, length)
|
tokenline := make([]string, length)
|
||||||
tokenline[0] = nick
|
tokenline[0] = nick
|
||||||
@ -1122,7 +1121,8 @@ var (
|
|||||||
func (session *Session) SendRawMessage(message ircmsg.IrcMessage, blocking bool) error {
|
func (session *Session) SendRawMessage(message ircmsg.IrcMessage, blocking bool) error {
|
||||||
// use dumb hack to force the last param to be a trailing param if required
|
// use dumb hack to force the last param to be a trailing param if required
|
||||||
var usedTrailingHack bool
|
var usedTrailingHack bool
|
||||||
if commandsThatMustUseTrailing[message.Command] && len(message.Params) > 0 {
|
config := session.client.server.Config()
|
||||||
|
if config.Server.Compatibility.forceTrailing && commandsThatMustUseTrailing[message.Command] && len(message.Params) > 0 {
|
||||||
lastParam := message.Params[len(message.Params)-1]
|
lastParam := message.Params[len(message.Params)-1]
|
||||||
// to force trailing, we ensure the final param contains a space
|
// to force trailing, we ensure the final param contains a space
|
||||||
if strings.IndexByte(lastParam, ' ') == -1 {
|
if strings.IndexByte(lastParam, ' ') == -1 {
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"code.cloudfoundry.org/bytefmt"
|
"code.cloudfoundry.org/bytefmt"
|
||||||
"github.com/oragono/oragono/irc/connection_limits"
|
"github.com/oragono/oragono/irc/connection_limits"
|
||||||
"github.com/oragono/oragono/irc/custime"
|
"github.com/oragono/oragono/irc/custime"
|
||||||
|
"github.com/oragono/oragono/irc/isupport"
|
||||||
"github.com/oragono/oragono/irc/languages"
|
"github.com/oragono/oragono/irc/languages"
|
||||||
"github.com/oragono/oragono/irc/logger"
|
"github.com/oragono/oragono/irc/logger"
|
||||||
"github.com/oragono/oragono/irc/modes"
|
"github.com/oragono/oragono/irc/modes"
|
||||||
@ -280,15 +281,22 @@ type Config struct {
|
|||||||
STS STSConfig
|
STS STSConfig
|
||||||
CheckIdent bool `yaml:"check-ident"`
|
CheckIdent bool `yaml:"check-ident"`
|
||||||
MOTD string
|
MOTD string
|
||||||
|
motdLines []string
|
||||||
MOTDFormatting bool `yaml:"motd-formatting"`
|
MOTDFormatting bool `yaml:"motd-formatting"`
|
||||||
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
||||||
proxyAllowedFromNets []net.IPNet
|
proxyAllowedFromNets []net.IPNet
|
||||||
WebIRC []webircConfig `yaml:"webirc"`
|
WebIRC []webircConfig `yaml:"webirc"`
|
||||||
MaxSendQString string `yaml:"max-sendq"`
|
MaxSendQString string `yaml:"max-sendq"`
|
||||||
MaxSendQBytes int
|
MaxSendQBytes int
|
||||||
AllowPlaintextResume bool `yaml:"allow-plaintext-resume"`
|
AllowPlaintextResume bool `yaml:"allow-plaintext-resume"`
|
||||||
ConnectionLimiter connection_limits.LimiterConfig `yaml:"connection-limits"`
|
Compatibility struct {
|
||||||
ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
|
ForceTrailing *bool `yaml:"force-trailing"`
|
||||||
|
forceTrailing bool
|
||||||
|
SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"`
|
||||||
|
}
|
||||||
|
isupport isupport.List
|
||||||
|
ConnectionLimiter connection_limits.LimiterConfig `yaml:"connection-limits"`
|
||||||
|
ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
|
||||||
}
|
}
|
||||||
|
|
||||||
Languages struct {
|
Languages struct {
|
||||||
@ -385,7 +393,7 @@ func (conf *Config) OperatorClasses() (map[string]*OperClass, error) {
|
|||||||
|
|
||||||
// get inhereted info from other operclasses
|
// get inhereted info from other operclasses
|
||||||
if len(info.Extends) > 0 {
|
if len(info.Extends) > 0 {
|
||||||
einfo, _ := ocs[info.Extends]
|
einfo := ocs[info.Extends]
|
||||||
|
|
||||||
for capab := range einfo.Capabilities {
|
for capab := range einfo.Capabilities {
|
||||||
oc.Capabilities[capab] = true
|
oc.Capabilities[capab] = true
|
||||||
@ -698,6 +706,20 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
config.Channels.Registration.MaxChannelsPerAccount = 15
|
config.Channels.Registration.MaxChannelsPerAccount = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceTrailingPtr := config.Server.Compatibility.ForceTrailing
|
||||||
|
if forceTrailingPtr != nil {
|
||||||
|
config.Server.Compatibility.forceTrailing = *forceTrailingPtr
|
||||||
|
} else {
|
||||||
|
config.Server.Compatibility.forceTrailing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
config.loadMOTD()
|
||||||
|
|
||||||
|
err = config.generateISupport()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// in the current implementation, we disable history by creating a history buffer
|
// in the current implementation, we disable history by creating a history buffer
|
||||||
// with zero capacity. but the `enabled` config option MUST be respected regardless
|
// with zero capacity. but the `enabled` config option MUST be respected regardless
|
||||||
// of this detail
|
// of this detail
|
||||||
|
@ -5,24 +5,20 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/oragono/oragono/irc/isupport"
|
|
||||||
"github.com/oragono/oragono/irc/languages"
|
"github.com/oragono/oragono/irc/languages"
|
||||||
"github.com/oragono/oragono/irc/modes"
|
"github.com/oragono/oragono/irc/modes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (server *Server) Config() (config *Config) {
|
func (server *Server) Config() (config *Config) {
|
||||||
server.configurableStateMutex.RLock()
|
return (*Config)(atomic.LoadPointer(&server.config))
|
||||||
config = server.config
|
|
||||||
server.configurableStateMutex.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) ISupport() *isupport.List {
|
func (server *Server) SetConfig(config *Config) {
|
||||||
server.configurableStateMutex.RLock()
|
atomic.StorePointer(&server.config, unsafe.Pointer(config))
|
||||||
defer server.configurableStateMutex.RUnlock()
|
|
||||||
return server.isupport
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) Limits() Limits {
|
func (server *Server) Limits() Limits {
|
||||||
@ -54,9 +50,7 @@ func (server *Server) GetOperator(name string) (oper *Oper) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
server.configurableStateMutex.RLock()
|
return server.Config().operators[name]
|
||||||
defer server.configurableStateMutex.RUnlock()
|
|
||||||
return server.config.operators[name]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) Languages() (lm *languages.Manager) {
|
func (server *Server) Languages() (lm *languages.Manager) {
|
||||||
|
@ -298,7 +298,9 @@ func accVerifyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb
|
|||||||
|
|
||||||
// AUTHENTICATE [<mechanism>|<data>|*]
|
// AUTHENTICATE [<mechanism>|<data>|*]
|
||||||
func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
|
config := server.Config()
|
||||||
details := client.Details()
|
details := client.Details()
|
||||||
|
|
||||||
if details.account != "" {
|
if details.account != "" {
|
||||||
rb.Add(nil, server.name, ERR_SASLALREADY, details.nick, client.t("You're already logged into an account"))
|
rb.Add(nil, server.name, ERR_SASLALREADY, details.nick, client.t("You're already logged into an account"))
|
||||||
return false
|
return false
|
||||||
@ -321,7 +323,14 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
|
|||||||
if mechanismIsEnabled {
|
if mechanismIsEnabled {
|
||||||
client.saslInProgress = true
|
client.saslInProgress = true
|
||||||
client.saslMechanism = mechanism
|
client.saslMechanism = mechanism
|
||||||
rb.Add(nil, server.name, "AUTHENTICATE", "+")
|
if !config.Server.Compatibility.SendUnprefixedSasl {
|
||||||
|
// normal behavior
|
||||||
|
rb.Add(nil, server.name, "AUTHENTICATE", "+")
|
||||||
|
} else {
|
||||||
|
// gross hack: send a raw message to ensure no tags or prefix
|
||||||
|
rb.Flush(true)
|
||||||
|
rb.session.SendRawMessage(ircmsg.MakeMessage(nil, "", "AUTHENTICATE", "+"), true)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed"))
|
rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed"))
|
||||||
}
|
}
|
||||||
@ -1175,20 +1184,14 @@ func inviteHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
func isonHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func isonHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
var nicks = msg.Params
|
var nicks = msg.Params
|
||||||
|
|
||||||
var err error
|
ison := make([]string, 0, len(msg.Params))
|
||||||
var casefoldedNick string
|
|
||||||
ison := make([]string, 0)
|
|
||||||
for _, nick := range nicks {
|
for _, nick := range nicks {
|
||||||
casefoldedNick, err = CasefoldName(nick)
|
if iclient := server.clients.Get(nick); iclient != nil {
|
||||||
if err != nil {
|
ison = append(ison, iclient.Nick())
|
||||||
continue
|
|
||||||
}
|
|
||||||
if iclient := server.clients.Get(casefoldedNick); iclient != nil {
|
|
||||||
ison = append(ison, iclient.nick)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.Add(nil, server.name, RPL_ISON, client.nick, strings.Join(nicks, " "))
|
rb.Add(nil, server.name, RPL_ISON, client.nick, strings.Join(ison, " "))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2089,7 +2092,7 @@ func npcaHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
|
|
||||||
// OPER <name> <password>
|
// OPER <name> <password>
|
||||||
func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
if client.HasMode(modes.Operator) == true {
|
if client.HasMode(modes.Operator) {
|
||||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "OPER", client.t("You're already opered-up!"))
|
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "OPER", client.t("You're already opered-up!"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,13 @@ type List struct {
|
|||||||
// NewList returns a new List
|
// NewList returns a new List
|
||||||
func NewList() *List {
|
func NewList() *List {
|
||||||
var il List
|
var il List
|
||||||
|
il.Initialize()
|
||||||
|
return &il
|
||||||
|
}
|
||||||
|
|
||||||
|
func (il *List) Initialize() {
|
||||||
il.Tokens = make(map[string]*string)
|
il.Tokens = make(map[string]*string)
|
||||||
il.CachedReply = make([][]string, 0)
|
il.CachedReply = make([][]string, 0)
|
||||||
return &il
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds an RPL_ISUPPORT token to our internal list
|
// Add adds an RPL_ISUPPORT token to our internal list
|
||||||
|
@ -170,7 +170,7 @@ func SplitChannelMembershipPrefixes(target string) (prefixes string, name string
|
|||||||
prefixes = target[:i+1]
|
prefixes = target[:i+1]
|
||||||
name = target[i+1:]
|
name = target[i+1:]
|
||||||
default:
|
default:
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,5 +36,4 @@ func (serversem *ServerSemaphores) Initialize() {
|
|||||||
capacity = MaxServerSemaphoreCapacity
|
capacity = MaxServerSemaphoreCapacity
|
||||||
}
|
}
|
||||||
serversem.ClientDestroy.Initialize(capacity)
|
serversem.ClientDestroy.Initialize(capacity)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
127
irc/server.go
127
irc/server.go
@ -19,11 +19,11 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goshuirc/irc-go/ircfmt"
|
"github.com/goshuirc/irc-go/ircfmt"
|
||||||
"github.com/oragono/oragono/irc/caps"
|
"github.com/oragono/oragono/irc/caps"
|
||||||
"github.com/oragono/oragono/irc/connection_limits"
|
"github.com/oragono/oragono/irc/connection_limits"
|
||||||
"github.com/oragono/oragono/irc/isupport"
|
|
||||||
"github.com/oragono/oragono/irc/logger"
|
"github.com/oragono/oragono/irc/logger"
|
||||||
"github.com/oragono/oragono/irc/modes"
|
"github.com/oragono/oragono/irc/modes"
|
||||||
"github.com/oragono/oragono/irc/sno"
|
"github.com/oragono/oragono/irc/sno"
|
||||||
@ -61,37 +61,34 @@ type ListenerWrapper struct {
|
|||||||
|
|
||||||
// Server is the main Oragono server.
|
// Server is the main Oragono server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
accounts AccountManager
|
accounts AccountManager
|
||||||
channels ChannelManager
|
channels ChannelManager
|
||||||
channelRegistry ChannelRegistry
|
channelRegistry ChannelRegistry
|
||||||
clients ClientManager
|
clients ClientManager
|
||||||
config *Config
|
config unsafe.Pointer
|
||||||
configFilename string
|
configFilename string
|
||||||
configurableStateMutex sync.RWMutex // tier 1; generic protection for server state modified by rehash()
|
connectionLimiter *connection_limits.Limiter
|
||||||
connectionLimiter *connection_limits.Limiter
|
connectionThrottler *connection_limits.Throttler
|
||||||
connectionThrottler *connection_limits.Throttler
|
ctime time.Time
|
||||||
ctime time.Time
|
dlines *DLineManager
|
||||||
dlines *DLineManager
|
helpIndexManager HelpIndexManager
|
||||||
helpIndexManager HelpIndexManager
|
klines *KLineManager
|
||||||
isupport *isupport.List
|
listeners map[string]*ListenerWrapper
|
||||||
klines *KLineManager
|
logger *logger.Manager
|
||||||
listeners map[string]*ListenerWrapper
|
monitorManager *MonitorManager
|
||||||
logger *logger.Manager
|
name string
|
||||||
monitorManager *MonitorManager
|
nameCasefolded string
|
||||||
motdLines []string
|
rehashMutex sync.Mutex // tier 4
|
||||||
name string
|
rehashSignal chan os.Signal
|
||||||
nameCasefolded string
|
pprofServer *http.Server
|
||||||
rehashMutex sync.Mutex // tier 4
|
resumeManager ResumeManager
|
||||||
rehashSignal chan os.Signal
|
signals chan os.Signal
|
||||||
pprofServer *http.Server
|
snomasks *SnoManager
|
||||||
resumeManager ResumeManager
|
store *buntdb.DB
|
||||||
signals chan os.Signal
|
torLimiter connection_limits.TorLimiter
|
||||||
snomasks *SnoManager
|
whoWas WhoWasList
|
||||||
store *buntdb.DB
|
stats Stats
|
||||||
torLimiter connection_limits.TorLimiter
|
semaphores ServerSemaphores
|
||||||
whoWas WhoWasList
|
|
||||||
stats Stats
|
|
||||||
semaphores ServerSemaphores
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -140,13 +137,12 @@ func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setISupport sets up our RPL_ISUPPORT reply.
|
// setISupport sets up our RPL_ISUPPORT reply.
|
||||||
func (server *Server) setISupport() (err error) {
|
func (config *Config) generateISupport() (err error) {
|
||||||
maxTargetsString := strconv.Itoa(maxTargets)
|
maxTargetsString := strconv.Itoa(maxTargets)
|
||||||
|
|
||||||
config := server.Config()
|
|
||||||
|
|
||||||
// add RPL_ISUPPORT tokens
|
// add RPL_ISUPPORT tokens
|
||||||
isupport := isupport.NewList()
|
isupport := &config.Server.isupport
|
||||||
|
isupport.Initialize()
|
||||||
isupport.Add("AWAYLEN", strconv.Itoa(config.Limits.AwayLen))
|
isupport.Add("AWAYLEN", strconv.Itoa(config.Limits.AwayLen))
|
||||||
isupport.Add("CASEMAPPING", "ascii")
|
isupport.Add("CASEMAPPING", "ascii")
|
||||||
isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), "", modes.Modes{modes.UserLimit, modes.Key}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret}.String()}, ","))
|
isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), "", modes.Modes{modes.UserLimit, modes.Key}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret}.String()}, ","))
|
||||||
@ -174,23 +170,9 @@ func (server *Server) setISupport() (err error) {
|
|||||||
isupport.Add("UTF8MAPPING", casemappingName)
|
isupport.Add("UTF8MAPPING", casemappingName)
|
||||||
|
|
||||||
err = isupport.RegenerateCachedReply()
|
err = isupport.RegenerateCachedReply()
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
server.configurableStateMutex.Lock()
|
|
||||||
server.isupport = isupport
|
|
||||||
server.configurableStateMutex.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadChannelList(channel *Channel, list string, maskMode modes.Mode) {
|
|
||||||
if list == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
channel.lists[maskMode].AddAll(strings.Split(list, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown shuts down the server.
|
// Shutdown shuts down the server.
|
||||||
func (server *Server) Shutdown() {
|
func (server *Server) Shutdown() {
|
||||||
//TODO(dan): Make sure we disallow new nicks
|
//TODO(dan): Make sure we disallow new nicks
|
||||||
@ -474,9 +456,7 @@ func (client *Client) t(originalString string) string {
|
|||||||
|
|
||||||
// MOTD serves the Message of the Day.
|
// MOTD serves the Message of the Day.
|
||||||
func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
|
func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
|
||||||
server.configurableStateMutex.RLock()
|
motdLines := server.Config().Server.motdLines
|
||||||
motdLines := server.motdLines
|
|
||||||
server.configurableStateMutex.RUnlock()
|
|
||||||
|
|
||||||
if len(motdLines) < 1 {
|
if len(motdLines) < 1 {
|
||||||
rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
|
rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
|
||||||
@ -535,9 +515,7 @@ func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
|
|||||||
tLanguages := target.Languages()
|
tLanguages := target.Languages()
|
||||||
if 0 < len(tLanguages) {
|
if 0 < len(tLanguages) {
|
||||||
params := []string{cnick, tnick}
|
params := []string{cnick, tnick}
|
||||||
for _, str := range client.server.Languages().Codes(tLanguages) {
|
params = append(params, client.server.Languages().Codes(tLanguages)...)
|
||||||
params = append(params, str)
|
|
||||||
}
|
|
||||||
params = append(params, client.t("can speak these languages"))
|
params = append(params, client.t("can speak these languages"))
|
||||||
rb.Add(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
|
rb.Add(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
|
||||||
}
|
}
|
||||||
@ -609,7 +587,7 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
|
|||||||
return fmt.Errorf("Maximum line length (linelen) cannot be changed after launching the server, rehash aborted")
|
return fmt.Errorf("Maximum line length (linelen) cannot be changed after launching the server, rehash aborted")
|
||||||
} else if server.name != config.Server.Name {
|
} else if server.name != config.Server.Name {
|
||||||
return fmt.Errorf("Server name cannot be changed after launching the server, rehash aborted")
|
return fmt.Errorf("Server name cannot be changed after launching the server, rehash aborted")
|
||||||
} else if server.config.Datastore.Path != config.Datastore.Path {
|
} else if server.Config().Datastore.Path != config.Datastore.Path {
|
||||||
return fmt.Errorf("Datastore path cannot be changed after launching the server, rehash aborted")
|
return fmt.Errorf("Datastore path cannot be changed after launching the server, rehash aborted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -780,12 +758,8 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server.loadMOTD(config.Server.MOTD, config.Server.MOTDFormatting)
|
|
||||||
|
|
||||||
// save a pointer to the new config
|
// save a pointer to the new config
|
||||||
server.configurableStateMutex.Lock()
|
server.SetConfig(config)
|
||||||
server.config = config
|
|
||||||
server.configurableStateMutex.Unlock()
|
|
||||||
|
|
||||||
server.logger.Info("server", "Using datastore", config.Datastore.Path)
|
server.logger.Info("server", "Using datastore", config.Datastore.Path)
|
||||||
if initial {
|
if initial {
|
||||||
@ -798,13 +772,8 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
|
|||||||
|
|
||||||
// set RPL_ISUPPORT
|
// set RPL_ISUPPORT
|
||||||
var newISupportReplies [][]string
|
var newISupportReplies [][]string
|
||||||
oldISupportList := server.ISupport()
|
if oldConfig != nil {
|
||||||
err = server.setISupport()
|
newISupportReplies = oldConfig.Server.isupport.GetDifference(&config.Server.isupport)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if oldISupportList != nil {
|
|
||||||
newISupportReplies = oldISupportList.GetDifference(server.ISupport())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are now open for business
|
// we are now open for business
|
||||||
@ -859,11 +828,9 @@ func (server *Server) setupPprofListener(config *Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) loadMOTD(motdPath string, useFormatting bool) error {
|
func (config *Config) loadMOTD() (err error) {
|
||||||
server.logger.Info("server", "Using MOTD", motdPath)
|
if config.Server.MOTD != "" {
|
||||||
motdLines := make([]string, 0)
|
file, err := os.Open(config.Server.MOTD)
|
||||||
if motdPath != "" {
|
|
||||||
file, err := os.Open(motdPath)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
@ -875,7 +842,7 @@ func (server *Server) loadMOTD(motdPath string, useFormatting bool) error {
|
|||||||
}
|
}
|
||||||
line = strings.TrimRight(line, "\r\n")
|
line = strings.TrimRight(line, "\r\n")
|
||||||
|
|
||||||
if useFormatting {
|
if config.Server.MOTDFormatting {
|
||||||
line = ircfmt.Unescape(line)
|
line = ircfmt.Unescape(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,17 +850,11 @@ func (server *Server) loadMOTD(motdPath string, useFormatting bool) error {
|
|||||||
// bursting it out to clients easier
|
// bursting it out to clients easier
|
||||||
line = fmt.Sprintf("- %s", line)
|
line = fmt.Sprintf("- %s", line)
|
||||||
|
|
||||||
motdLines = append(motdLines, line)
|
config.Server.motdLines = append(config.Server.motdLines, line)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
server.configurableStateMutex.Lock()
|
|
||||||
server.motdLines = motdLines
|
|
||||||
server.configurableStateMutex.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) loadDatastore(config *Config) error {
|
func (server *Server) loadDatastore(config *Config) error {
|
||||||
|
@ -52,7 +52,7 @@ func (m *SnoManager) RemoveMasks(client *Client, masks ...sno.Mask) {
|
|||||||
for _, mask := range masks {
|
for _, mask := range masks {
|
||||||
currentClientList := m.sendLists[mask]
|
currentClientList := m.sendLists[mask]
|
||||||
|
|
||||||
if currentClientList == nil || len(currentClientList) == 0 {
|
if len(currentClientList) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ func (m *SnoManager) RemoveClient(client *Client) {
|
|||||||
for mask := range m.sendLists {
|
for mask := range m.sendLists {
|
||||||
currentClientList := m.sendLists[mask]
|
currentClientList := m.sendLists[mask]
|
||||||
|
|
||||||
if currentClientList == nil || len(currentClientList) == 0 {
|
if len(currentClientList) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ func (m *SnoManager) Send(mask sno.Mask, content string) {
|
|||||||
|
|
||||||
currentClientList := m.sendLists[mask]
|
currentClientList := m.sendLists[mask]
|
||||||
|
|
||||||
if currentClientList == nil || len(currentClientList) == 0 {
|
if len(currentClientList) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
oragono.yaml
15
oragono.yaml
@ -125,6 +125,21 @@ server:
|
|||||||
# this should be big enough to hold bursts of channel/direct messages
|
# this should be big enough to hold bursts of channel/direct messages
|
||||||
max-sendq: 16k
|
max-sendq: 16k
|
||||||
|
|
||||||
|
# compatibility with legacy clients
|
||||||
|
compatibility:
|
||||||
|
# many clients require that the final parameter of certain messages be an
|
||||||
|
# RFC1459 trailing parameter, i.e., prefixed with :, whether or not this is
|
||||||
|
# actually required. this forces Oragono to send those parameters
|
||||||
|
# as trailings. this is recommended unless you're testing clients for conformance;
|
||||||
|
# defaults to true when unset for that reason.
|
||||||
|
force-trailing: true
|
||||||
|
|
||||||
|
# some clients (ZNC 1.6.x and lower, Pidgin 2.12 and lower, Adium) do not
|
||||||
|
# respond correctly to SASL messages with the server name as a prefix:
|
||||||
|
# https://github.com/znc/znc/issues/1212
|
||||||
|
# this works around that bug, allowing them to use SASL.
|
||||||
|
send-unprefixed-sasl: true
|
||||||
|
|
||||||
# maximum number of connections per subnet
|
# maximum number of connections per subnet
|
||||||
connection-limits:
|
connection-limits:
|
||||||
# whether to enforce connection limits or not
|
# whether to enforce connection limits or not
|
||||||
|
Loading…
Reference in New Issue
Block a user