mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 03:49:27 +01:00
parent
9033d97c6f
commit
ba72d3acfc
@ -94,6 +94,13 @@ def convert(infile):
|
|||||||
out['channels'][chname]['topicSetBy'] = parts[3]
|
out['channels'][chname]['topicSetBy'] = parts[3]
|
||||||
elif category == 'private:topic:ts':
|
elif category == 'private:topic:ts':
|
||||||
out['channels'][chname]['topicSetAt'] = to_unixnano(parts[3])
|
out['channels'][chname]['topicSetAt'] = to_unixnano(parts[3])
|
||||||
|
elif category == 'private:mlockext':
|
||||||
|
# the channel forward mode is +L on insp/unreal, +f on charybdis
|
||||||
|
# charybdis has a +L ("large banlist") taking no argument
|
||||||
|
# and unreal has a +f ("flood limit") taking two colon-delimited numbers,
|
||||||
|
# so check for an argument that starts with a #
|
||||||
|
if parts[3].startswith('L#') or parts[3].startswith('f#'):
|
||||||
|
out['channels'][chname]['forward'] = parts[3][1:]
|
||||||
elif category == 'CA':
|
elif category == 'CA':
|
||||||
# channel access lists
|
# channel access lists
|
||||||
# CA #mychannel shivaram +AFORafhioqrstv 1600134478 shivaram
|
# CA #mychannel shivaram +AFORafhioqrstv 1600134478 shivaram
|
||||||
|
@ -28,6 +28,7 @@ type Channel struct {
|
|||||||
flags modes.ModeSet
|
flags modes.ModeSet
|
||||||
lists map[modes.Mode]*UserMaskSet
|
lists map[modes.Mode]*UserMaskSet
|
||||||
key string
|
key string
|
||||||
|
forward string
|
||||||
members MemberSet
|
members MemberSet
|
||||||
membersCache []*Client // allow iteration over channel members without holding the lock
|
membersCache []*Client // allow iteration over channel members without holding the lock
|
||||||
name string
|
name string
|
||||||
@ -133,6 +134,7 @@ func (channel *Channel) applyRegInfo(chanReg RegisteredChannel) {
|
|||||||
channel.key = chanReg.Key
|
channel.key = chanReg.Key
|
||||||
channel.userLimit = chanReg.UserLimit
|
channel.userLimit = chanReg.UserLimit
|
||||||
channel.settings = chanReg.Settings
|
channel.settings = chanReg.Settings
|
||||||
|
channel.forward = chanReg.Forward
|
||||||
|
|
||||||
for _, mode := range chanReg.Modes {
|
for _, mode := range chanReg.Modes {
|
||||||
channel.flags.SetMode(mode, true)
|
channel.flags.SetMode(mode, true)
|
||||||
@ -163,6 +165,7 @@ func (channel *Channel) ExportRegistration(includeFlags uint) (info RegisteredCh
|
|||||||
|
|
||||||
if includeFlags&IncludeModes != 0 {
|
if includeFlags&IncludeModes != 0 {
|
||||||
info.Key = channel.key
|
info.Key = channel.key
|
||||||
|
info.Forward = channel.forward
|
||||||
info.Modes = channel.flags.AllModes()
|
info.Modes = channel.flags.AllModes()
|
||||||
info.UserLimit = channel.userLimit
|
info.UserLimit = channel.userLimit
|
||||||
}
|
}
|
||||||
@ -612,20 +615,27 @@ func (channel *Channel) modeStrings(client *Client) (result []string) {
|
|||||||
isMember := hasPrivs || channel.members[client] != nil
|
isMember := hasPrivs || channel.members[client] != nil
|
||||||
showKey := isMember && (channel.key != "")
|
showKey := isMember && (channel.key != "")
|
||||||
showUserLimit := channel.userLimit > 0
|
showUserLimit := channel.userLimit > 0
|
||||||
|
showForward := channel.forward != ""
|
||||||
|
|
||||||
mods := "+"
|
var mods strings.Builder
|
||||||
|
mods.WriteRune('+')
|
||||||
|
|
||||||
// flags with args
|
// flags with args
|
||||||
if showKey {
|
if showKey {
|
||||||
mods += modes.Key.String()
|
mods.WriteRune(rune(modes.Key))
|
||||||
}
|
}
|
||||||
if showUserLimit {
|
if showUserLimit {
|
||||||
mods += modes.UserLimit.String()
|
mods.WriteRune(rune(modes.UserLimit))
|
||||||
|
}
|
||||||
|
if showForward {
|
||||||
|
mods.WriteRune(rune(modes.Forward))
|
||||||
}
|
}
|
||||||
|
|
||||||
mods += channel.flags.String()
|
for _, m := range channel.flags.AllModes() {
|
||||||
|
mods.WriteRune(rune(m))
|
||||||
|
}
|
||||||
|
|
||||||
result = []string{mods}
|
result = []string{mods.String()}
|
||||||
|
|
||||||
// args for flags with args: The order must match above to keep
|
// args for flags with args: The order must match above to keep
|
||||||
// positional arguments in place.
|
// positional arguments in place.
|
||||||
@ -635,6 +645,9 @@ func (channel *Channel) modeStrings(client *Client) (result []string) {
|
|||||||
if showUserLimit {
|
if showUserLimit {
|
||||||
result = append(result, strconv.Itoa(channel.userLimit))
|
result = append(result, strconv.Itoa(channel.userLimit))
|
||||||
}
|
}
|
||||||
|
if showForward {
|
||||||
|
result = append(result, channel.forward)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -694,7 +707,7 @@ func (channel *Channel) AddHistoryItem(item history.Item, account string) (err e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join joins the given client to this channel (if they can be joined).
|
// Join joins the given client to this channel (if they can be joined).
|
||||||
func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *ResponseBuffer) error {
|
func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *ResponseBuffer) (joinErr error, forward string) {
|
||||||
details := client.Details()
|
details := client.Details()
|
||||||
|
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
@ -707,11 +720,12 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
chcount := len(channel.members)
|
chcount := len(channel.members)
|
||||||
_, alreadyJoined := channel.members[client]
|
_, alreadyJoined := channel.members[client]
|
||||||
persistentMode := channel.accountToUMode[details.account]
|
persistentMode := channel.accountToUMode[details.account]
|
||||||
|
forward = channel.forward
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
|
|
||||||
if alreadyJoined {
|
if alreadyJoined {
|
||||||
// no message needs to be sent
|
// no message needs to be sent
|
||||||
return nil
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0. SAJOIN always succeeds
|
// 0. SAJOIN always succeeds
|
||||||
@ -723,32 +737,33 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
client.CheckInvited(chcfname, createdAt)
|
client.CheckInvited(chcfname, createdAt)
|
||||||
if !hasPrivs {
|
if !hasPrivs {
|
||||||
if limit != 0 && chcount >= limit {
|
if limit != 0 && chcount >= limit {
|
||||||
return errLimitExceeded
|
return errLimitExceeded, forward
|
||||||
}
|
}
|
||||||
|
|
||||||
if chkey != "" && !utils.SecretTokensMatch(chkey, key) {
|
if chkey != "" && !utils.SecretTokensMatch(chkey, key) {
|
||||||
return errWrongChannelKey
|
return errWrongChannelKey, forward
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.flags.HasMode(modes.InviteOnly) &&
|
if channel.flags.HasMode(modes.InviteOnly) &&
|
||||||
!channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded) {
|
!channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded) {
|
||||||
return errInviteOnly
|
return errInviteOnly, forward
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
if channel.lists[modes.BanMask].Match(details.nickMaskCasefolded) &&
|
||||||
!channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) &&
|
!channel.lists[modes.ExceptMask].Match(details.nickMaskCasefolded) &&
|
||||||
!channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded) {
|
!channel.lists[modes.InviteMask].Match(details.nickMaskCasefolded) {
|
||||||
return errBanned
|
// do not forward people who are banned:
|
||||||
|
return errBanned, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if details.account == "" &&
|
if details.account == "" &&
|
||||||
(channel.flags.HasMode(modes.RegisteredOnly) || channel.server.Defcon() <= 2) {
|
(channel.flags.HasMode(modes.RegisteredOnly) || channel.server.Defcon() <= 2) {
|
||||||
return errRegisteredOnly
|
return errRegisteredOnly, forward
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if joinErr := client.addChannel(channel, rb == nil); joinErr != nil {
|
if joinErr := client.addChannel(channel, rb == nil); joinErr != nil {
|
||||||
return joinErr
|
return joinErr, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
|
client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
|
||||||
@ -795,7 +810,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rb == nil {
|
if rb == nil {
|
||||||
return nil
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var modestr string
|
var modestr string
|
||||||
@ -858,7 +873,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
rb.Flush(true)
|
rb.Flush(true)
|
||||||
|
|
||||||
channel.autoReplayHistory(client, rb, message.Msgid)
|
channel.autoReplayHistory(client, rb, message.Msgid)
|
||||||
return nil
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, skipMsgid string) {
|
func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, skipMsgid string) {
|
||||||
|
@ -83,12 +83,12 @@ func (cm *ChannelManager) Get(name string) (channel *Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join causes `client` to join the channel named `name`, creating it if necessary.
|
// Join causes `client` to join the channel named `name`, creating it if necessary.
|
||||||
func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin bool, rb *ResponseBuffer) error {
|
func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin bool, rb *ResponseBuffer) (err error, forward string) {
|
||||||
server := client.server
|
server := client.server
|
||||||
casefoldedName, err := CasefoldChannel(name)
|
casefoldedName, err := CasefoldChannel(name)
|
||||||
skeleton, skerr := Skeleton(name)
|
skeleton, skerr := Skeleton(name)
|
||||||
if err != nil || skerr != nil || len(casefoldedName) > server.Config().Limits.ChannelLen {
|
if err != nil || skerr != nil || len(casefoldedName) > server.Config().Limits.ChannelLen {
|
||||||
return errNoSuchChannel
|
return errNoSuchChannel, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
channel, err := func() (*Channel, error) {
|
channel, err := func() (*Channel, error) {
|
||||||
@ -128,15 +128,15 @@ func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.EnsureLoaded()
|
channel.EnsureLoaded()
|
||||||
err = channel.Join(client, key, isSajoin, rb)
|
err, forward = channel.Join(client, key, isSajoin, rb)
|
||||||
|
|
||||||
cm.maybeCleanup(channel, true)
|
cm.maybeCleanup(channel, true)
|
||||||
|
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *ChannelManager) maybeCleanup(channel *Channel, afterJoin bool) {
|
func (cm *ChannelManager) maybeCleanup(channel *Channel, afterJoin bool) {
|
||||||
|
@ -35,6 +35,7 @@ const (
|
|||||||
keyChannelAccountToUMode = "channel.accounttoumode %s"
|
keyChannelAccountToUMode = "channel.accounttoumode %s"
|
||||||
keyChannelUserLimit = "channel.userlimit %s"
|
keyChannelUserLimit = "channel.userlimit %s"
|
||||||
keyChannelSettings = "channel.settings %s"
|
keyChannelSettings = "channel.settings %s"
|
||||||
|
keyChannelForward = "channel.forward %s"
|
||||||
|
|
||||||
keyChannelPurged = "channel.purged %s"
|
keyChannelPurged = "channel.purged %s"
|
||||||
)
|
)
|
||||||
@ -56,6 +57,7 @@ var (
|
|||||||
keyChannelAccountToUMode,
|
keyChannelAccountToUMode,
|
||||||
keyChannelUserLimit,
|
keyChannelUserLimit,
|
||||||
keyChannelSettings,
|
keyChannelSettings,
|
||||||
|
keyChannelForward,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,6 +96,8 @@ type RegisteredChannel struct {
|
|||||||
Modes []modes.Mode
|
Modes []modes.Mode
|
||||||
// Key represents the channel key / password
|
// Key represents the channel key / password
|
||||||
Key string
|
Key string
|
||||||
|
// Forward is the forwarding/overflow (+f) channel
|
||||||
|
Forward string
|
||||||
// UserLimit is the user limit (0 for no limit)
|
// UserLimit is the user limit (0 for no limit)
|
||||||
UserLimit int
|
UserLimit int
|
||||||
// AccountToUMode maps user accounts to their persistent channel modes (e.g., +q, +h)
|
// AccountToUMode maps user accounts to their persistent channel modes (e.g., +q, +h)
|
||||||
@ -208,6 +212,7 @@ func (reg *ChannelRegistry) LoadChannel(nameCasefolded string) (info RegisteredC
|
|||||||
password, _ := tx.Get(fmt.Sprintf(keyChannelPassword, channelKey))
|
password, _ := tx.Get(fmt.Sprintf(keyChannelPassword, channelKey))
|
||||||
modeString, _ := tx.Get(fmt.Sprintf(keyChannelModes, channelKey))
|
modeString, _ := tx.Get(fmt.Sprintf(keyChannelModes, channelKey))
|
||||||
userLimitString, _ := tx.Get(fmt.Sprintf(keyChannelUserLimit, channelKey))
|
userLimitString, _ := tx.Get(fmt.Sprintf(keyChannelUserLimit, channelKey))
|
||||||
|
forward, _ := tx.Get(fmt.Sprintf(keyChannelForward, channelKey))
|
||||||
banlistString, _ := tx.Get(fmt.Sprintf(keyChannelBanlist, channelKey))
|
banlistString, _ := tx.Get(fmt.Sprintf(keyChannelBanlist, channelKey))
|
||||||
exceptlistString, _ := tx.Get(fmt.Sprintf(keyChannelExceptlist, channelKey))
|
exceptlistString, _ := tx.Get(fmt.Sprintf(keyChannelExceptlist, channelKey))
|
||||||
invitelistString, _ := tx.Get(fmt.Sprintf(keyChannelInvitelist, channelKey))
|
invitelistString, _ := tx.Get(fmt.Sprintf(keyChannelInvitelist, channelKey))
|
||||||
@ -249,6 +254,7 @@ func (reg *ChannelRegistry) LoadChannel(nameCasefolded string) (info RegisteredC
|
|||||||
AccountToUMode: accountToUMode,
|
AccountToUMode: accountToUMode,
|
||||||
UserLimit: int(userLimit),
|
UserLimit: int(userLimit),
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
|
Forward: forward,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -361,6 +367,7 @@ func (reg *ChannelRegistry) saveChannel(tx *buntdb.Tx, channelInfo RegisteredCha
|
|||||||
modeString := modes.Modes(channelInfo.Modes).String()
|
modeString := modes.Modes(channelInfo.Modes).String()
|
||||||
tx.Set(fmt.Sprintf(keyChannelModes, channelKey), modeString, nil)
|
tx.Set(fmt.Sprintf(keyChannelModes, channelKey), modeString, nil)
|
||||||
tx.Set(fmt.Sprintf(keyChannelUserLimit, channelKey), strconv.Itoa(channelInfo.UserLimit), nil)
|
tx.Set(fmt.Sprintf(keyChannelUserLimit, channelKey), strconv.Itoa(channelInfo.UserLimit), nil)
|
||||||
|
tx.Set(fmt.Sprintf(keyChannelForward, channelKey), channelInfo.Forward, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if includeFlags&IncludeLists != 0 {
|
if includeFlags&IncludeLists != 0 {
|
||||||
|
@ -517,3 +517,9 @@ func (channel *Channel) SetSettings(settings ChannelSettings) {
|
|||||||
channel.stateMutex.Unlock()
|
channel.stateMutex.Unlock()
|
||||||
channel.MarkDirty(IncludeSettings)
|
channel.MarkDirty(IncludeSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) setForward(forward string) {
|
||||||
|
channel.stateMutex.Lock()
|
||||||
|
channel.forward = forward
|
||||||
|
channel.stateMutex.Unlock()
|
||||||
|
}
|
||||||
|
@ -1192,9 +1192,16 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
if len(keys) > i {
|
if len(keys) > i {
|
||||||
key = keys[i]
|
key = keys[i]
|
||||||
}
|
}
|
||||||
err := server.channels.Join(client, name, key, false, rb)
|
err, forward := server.channels.Join(client, name, key, false, rb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendJoinError(client, name, rb, err)
|
if forward != "" {
|
||||||
|
rb.Add(nil, server.name, ERR_LINKCHANNEL, client.Nick(), utils.SafeErrorParam(name), forward, client.t("Forwarding to another channel"))
|
||||||
|
name = forward
|
||||||
|
err, _ = server.channels.Join(client, name, key, false, rb)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
sendJoinError(client, name, rb, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -1255,7 +1262,7 @@ func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
|
|
||||||
channels := strings.Split(channelString, ",")
|
channels := strings.Split(channelString, ",")
|
||||||
for _, chname := range channels {
|
for _, chname := range channels {
|
||||||
err := server.channels.Join(target, chname, "", true, rb)
|
err, _ := server.channels.Join(target, chname, "", true, rb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendJoinError(client, chname, rb, err)
|
sendJoinError(client, chname, rb, err)
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ type channelImport struct {
|
|||||||
Modes string
|
Modes string
|
||||||
Key string
|
Key string
|
||||||
Limit int
|
Limit int
|
||||||
|
Forward string
|
||||||
}
|
}
|
||||||
|
|
||||||
type databaseImport struct {
|
type databaseImport struct {
|
||||||
@ -187,6 +188,11 @@ func doImportDBGeneric(config *Config, dbImport databaseImport, credsType Creden
|
|||||||
if chInfo.Limit > 0 {
|
if chInfo.Limit > 0 {
|
||||||
tx.Set(fmt.Sprintf(keyChannelUserLimit, cfchname), strconv.Itoa(chInfo.Limit), nil)
|
tx.Set(fmt.Sprintf(keyChannelUserLimit, cfchname), strconv.Itoa(chInfo.Limit), nil)
|
||||||
}
|
}
|
||||||
|
if chInfo.Forward != "" {
|
||||||
|
if _, err := CasefoldChannel(chInfo.Forward); err == nil {
|
||||||
|
tx.Set(fmt.Sprintf(keyChannelForward, cfchname), chInfo.Forward, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if warnSkeletons {
|
if warnSkeletons {
|
||||||
|
25
irc/modes.go
25
irc/modes.go
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/oragono/oragono/irc/modes"
|
"github.com/oragono/oragono/irc/modes"
|
||||||
"github.com/oragono/oragono/irc/sno"
|
"github.com/oragono/oragono/irc/sno"
|
||||||
|
"github.com/oragono/oragono/irc/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -254,6 +255,28 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
|||||||
applied = append(applied, change)
|
applied = append(applied, change)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case modes.Forward:
|
||||||
|
switch change.Op {
|
||||||
|
case modes.Add:
|
||||||
|
ch := client.server.channels.Get(change.Arg)
|
||||||
|
if ch == nil {
|
||||||
|
rb.Add(nil, client.server.name, ERR_INVALIDMODEPARAM, details.nick, utils.SafeErrorParam(change.Arg), fmt.Sprintf(client.t("No such channel")))
|
||||||
|
} else if ch == channel {
|
||||||
|
rb.Add(nil, client.server.name, ERR_INVALIDMODEPARAM, details.nick, utils.SafeErrorParam(change.Arg), fmt.Sprintf(client.t("You can't forward a channel to itself")))
|
||||||
|
} else {
|
||||||
|
if !ch.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||||
|
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, details.nick, ch.Name(), client.t("You must be a channel operator in the channel you are forwarding to"))
|
||||||
|
} else {
|
||||||
|
change.Arg = ch.Name()
|
||||||
|
channel.setForward(change.Arg)
|
||||||
|
applied = append(applied, change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case modes.Remove:
|
||||||
|
channel.setForward("")
|
||||||
|
applied = append(applied, change)
|
||||||
|
}
|
||||||
|
|
||||||
case modes.Key:
|
case modes.Key:
|
||||||
switch change.Op {
|
switch change.Op {
|
||||||
case modes.Add:
|
case modes.Add:
|
||||||
@ -302,7 +325,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
|
|||||||
case modes.BanMask, modes.ExceptMask, modes.InviteMask:
|
case modes.BanMask, modes.ExceptMask, modes.InviteMask:
|
||||||
includeFlags |= IncludeLists
|
includeFlags |= IncludeLists
|
||||||
case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
|
case modes.ChannelFounder, modes.ChannelAdmin, modes.ChannelOperator, modes.Halfop, modes.Voice:
|
||||||
// these are never persisted currently, but might be in the future (see discussion on #729)
|
// these are persisted on the client object, via (*Channel).applyModeToMember
|
||||||
default:
|
default:
|
||||||
includeFlags |= IncludeModes
|
includeFlags |= IncludeModes
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ var (
|
|||||||
SupportedChannelModes = Modes{
|
SupportedChannelModes = Modes{
|
||||||
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
|
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
|
||||||
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
|
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
|
||||||
Secret, UserLimit, NoCTCP, Auditorium, OpModerated,
|
Secret, UserLimit, NoCTCP, Auditorium, OpModerated, Forward,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -130,6 +130,7 @@ const (
|
|||||||
UserLimit Mode = 'l' // flag arg
|
UserLimit Mode = 'l' // flag arg
|
||||||
NoCTCP Mode = 'C' // flag
|
NoCTCP Mode = 'C' // flag
|
||||||
OpModerated Mode = 'U' // flag
|
OpModerated Mode = 'U' // flag
|
||||||
|
Forward Mode = 'f' // flag arg
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -277,7 +278,7 @@ func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
|
|||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case UserLimit:
|
case UserLimit, Forward:
|
||||||
// don't require value when removing
|
// don't require value when removing
|
||||||
if change.Op == Add {
|
if change.Op == Add {
|
||||||
if len(params) > skipArgs {
|
if len(params) > skipArgs {
|
||||||
@ -445,7 +446,7 @@ func RplMyInfo() (param1, param2, param3 string) {
|
|||||||
sort.Sort(ByCodepoint(channelModes))
|
sort.Sort(ByCodepoint(channelModes))
|
||||||
|
|
||||||
// XXX enumerate these by hand, i can't see any way to DRY this
|
// XXX enumerate these by hand, i can't see any way to DRY this
|
||||||
channelParametrizedModes := Modes{BanMask, ExceptMask, InviteMask, Key, UserLimit}
|
channelParametrizedModes := Modes{BanMask, ExceptMask, InviteMask, Key, UserLimit, Forward}
|
||||||
channelParametrizedModes = append(channelParametrizedModes, ChannelUserModes...)
|
channelParametrizedModes = append(channelParametrizedModes, ChannelUserModes...)
|
||||||
sort.Sort(ByCodepoint(channelParametrizedModes))
|
sort.Sort(ByCodepoint(channelParametrizedModes))
|
||||||
|
|
||||||
@ -459,7 +460,7 @@ func ChanmodesToken() (result string) {
|
|||||||
// type B: modes with parameters
|
// type B: modes with parameters
|
||||||
B := Modes{Key}
|
B := Modes{Key}
|
||||||
// type C: modes that take a parameter only when set, never when unset
|
// type C: modes that take a parameter only when set, never when unset
|
||||||
C := Modes{UserLimit}
|
C := Modes{UserLimit, Forward}
|
||||||
// type D: modes without parameters
|
// type D: modes without parameters
|
||||||
D := Modes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret, NoCTCP, RegisteredOnly, RegisteredOnlySpeak, Auditorium, OpModerated}
|
D := Modes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret, NoCTCP, RegisteredOnly, RegisteredOnlySpeak, Auditorium, OpModerated}
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@ const (
|
|||||||
ERR_YOUWILLBEBANNED = "466"
|
ERR_YOUWILLBEBANNED = "466"
|
||||||
ERR_KEYSET = "467"
|
ERR_KEYSET = "467"
|
||||||
ERR_INVALIDUSERNAME = "468"
|
ERR_INVALIDUSERNAME = "468"
|
||||||
|
ERR_LINKCHANNEL = "470"
|
||||||
ERR_CHANNELISFULL = "471"
|
ERR_CHANNELISFULL = "471"
|
||||||
ERR_UNKNOWNMODE = "472"
|
ERR_UNKNOWNMODE = "472"
|
||||||
ERR_INVITEONLYCHAN = "473"
|
ERR_INVITEONLYCHAN = "473"
|
||||||
|
Loading…
Reference in New Issue
Block a user