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:
parent
53190ef131
commit
0f8ab4eaec
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
109
irc/server.go
109
irc/server.go
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user