3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

server: Add proposed RENAME command

This commit is contained in:
Daniel Oaks 2017-06-04 20:01:37 -06:00
parent 53190ef131
commit 0f8ab4eaec
5 changed files with 130 additions and 1 deletions

View File

@ -14,8 +14,8 @@ import (
type Capability string type Capability string
const ( const (
AccountTag Capability = "account-tag"
AccountNotify Capability = "account-notify" AccountNotify Capability = "account-notify"
AccountTag Capability = "account-tag"
AwayNotify Capability = "away-notify" AwayNotify Capability = "away-notify"
CapNotify Capability = "cap-notify" CapNotify Capability = "cap-notify"
ChgHost Capability = "chghost" ChgHost Capability = "chghost"
@ -26,6 +26,7 @@ const (
MessageIDs Capability = "draft/message-ids" MessageIDs Capability = "draft/message-ids"
MessageTags Capability = "draft/message-tags-0.2" MessageTags Capability = "draft/message-tags-0.2"
MultiPrefix Capability = "multi-prefix" MultiPrefix Capability = "multi-prefix"
Rename Capability = "draft/rename"
SASL Capability = "sasl" SASL Capability = "sasl"
ServerTime Capability = "server-time" ServerTime Capability = "server-time"
STS Capability = "draft/sts" STS Capability = "draft/sts"
@ -47,6 +48,7 @@ var (
// MaxLine is set during server startup // MaxLine is set during server startup
MessageTags: true, MessageTags: true,
MultiPrefix: true, MultiPrefix: true,
Rename: true,
// SASL is set during server startup // SASL is set during server startup
ServerTime: true, ServerTime: true,
// STS is set during server startup // STS is set during server startup

View File

@ -53,6 +53,12 @@ type RegisteredChannel struct {
Invitelist []string Invitelist []string
} }
// deleteChannelNoMutex deletes a given channel from our store.
func (server *Server) deleteChannelNoMutex(tx *buntdb.Tx, channelKey string) {
tx.Delete(fmt.Sprintf(keyChannelExists, channelKey))
server.registeredChannels[channelKey] = nil
}
// loadChannelNoMutex loads a channel from the store. // loadChannelNoMutex loads a channel from the store.
func (server *Server) loadChannelNoMutex(tx *buntdb.Tx, channelKey string) *RegisteredChannel { func (server *Server) loadChannelNoMutex(tx *buntdb.Tx, channelKey string) *RegisteredChannel {
// return loaded chan if it already exists // return loaded chan if it already exists

View File

@ -209,6 +209,10 @@ var Commands = map[string]Command{
handler: privmsgHandler, handler: privmsgHandler,
minParams: 2, minParams: 2,
}, },
"RENAME": {
handler: renameHandler,
minParams: 2,
},
"SANICK": { "SANICK": {
handler: sanickHandler, handler: sanickHandler,
minParams: 2, minParams: 2,

View File

@ -354,6 +354,14 @@ Replies to a PING. Used to check link connectivity.`,
text: `PRIVMSG <target>{,<target>} <text to be sent> text: `PRIVMSG <target>{,<target>} <text to be sent>
Sends the text to the given targets as a PRIVMSG.`, Sends the text to the given targets as a PRIVMSG.`,
},
"rename": {
text: `RENAME <channel> <newname> [<reason>]
Renames the given channel with the given reason, if possible.
For example:
RENAME #ircv2 #ircv3 :Protocol upgrades!`,
}, },
"sanick": { "sanick": {
oper: true, oper: true,

View File

@ -789,6 +789,115 @@ func pongHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
return false return false
} }
// RENAME <oldchan> <newchan> [<reason>]
//TODO(dan): Clean up this function so it doesn't look like an eldrich horror... prolly by putting it into a server.renameChannel function.
func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// get lots of locks... make sure nobody touches anything while we're doing this
server.registeredChannelsMutex.Lock()
defer server.registeredChannelsMutex.Unlock()
server.channels.ChansLock.Lock()
defer server.channels.ChansLock.Unlock()
oldName := strings.TrimSpace(msg.Params[0])
newName := strings.TrimSpace(msg.Params[1])
reason := "No reason"
if 2 < len(msg.Params) {
reason = msg.Params[2]
}
// check for all the reasons why the rename couldn't happen
casefoldedOldName, err := CasefoldChannel(oldName)
if err != nil {
//TODO(dan): Change this to ERR_CANNOTRENAME
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", oldName, "Old channel name is invalid")
return false
}
channel := server.channels.Chans[casefoldedOldName]
if channel == nil {
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, oldName, "No such channel")
return false
}
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
casefoldedNewName, err := CasefoldChannel(newName)
if err != nil {
//TODO(dan): Change this to ERR_CANNOTRENAME
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", newName, "New channel name is invalid")
return false
}
newChannel := server.channels.Chans[casefoldedNewName]
if newChannel != nil {
//TODO(dan): Change this to ERR_CHANNAMEINUSE
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", newName, "New channel name is in use")
return false
}
var canEdit bool
server.store.Update(func(tx *buntdb.Tx) error {
chanReg := server.loadChannelNoMutex(tx, casefoldedOldName)
if chanReg == nil || client.account == nil || client.account.Name == chanReg.Founder {
canEdit = true
}
chanReg = server.loadChannelNoMutex(tx, casefoldedNewName)
if chanReg != nil {
canEdit = false
}
return nil
})
if !canEdit {
//TODO(dan): Change this to ERR_CANNOTRENAME
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", oldName, "Only channel founders can change registered channels")
return false
}
// perform the channel rename
server.channels.Chans[casefoldedOldName] = nil
server.channels.Chans[casefoldedNewName] = channel
channel.name = strings.TrimSpace(msg.Params[1])
channel.nameCasefolded = casefoldedNewName
// rename stored channel info if any exists
server.store.Update(func(tx *buntdb.Tx) error {
chanReg := server.loadChannelNoMutex(tx, casefoldedOldName)
if chanReg == nil {
return nil
}
server.deleteChannelNoMutex(tx, casefoldedOldName)
chanReg.Name = newName
server.saveChannelNoMutex(tx, casefoldedNewName, *chanReg)
return nil
})
// send RENAME messages
for mcl := range channel.members {
if mcl.capabilities[Rename] {
mcl.Send(nil, client.nickMaskString, "RENAME", oldName, newName, reason)
} else {
mcl.Send(nil, mcl.nickMaskString, "PART", oldName, fmt.Sprintf("Channel renamed: %s", reason))
if mcl.capabilities[ExtendedJoin] {
accountName := "*"
if mcl.account != nil {
accountName = mcl.account.Name
}
mcl.Send(nil, mcl.nickMaskString, "JOIN", newName, accountName, mcl.realname)
} else {
mcl.Send(nil, mcl.nickMaskString, "JOIN", newName)
}
}
}
return false
}
// JOIN <channel>{,<channel>} [<key>{,<key>}] // JOIN <channel>{,<channel>} [<key>{,<key>}]
// JOIN 0 // JOIN 0
func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {