diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa6fee2..b5fcd5fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ New release of Oragono! ### Added * Operator classes, allowing for more finely-grained permissions for operators. +* Added support for IRCv3 capability [`chghost`](http://ircv3.net/specs/extensions/chghost-3.2.html). ### Changed * In the config file, "operator" changed to "opers", and new oper class is required. diff --git a/irc/capability.go b/irc/capability.go index 9318f984..8236b408 100644 --- a/irc/capability.go +++ b/irc/capability.go @@ -18,6 +18,7 @@ const ( AccountNotify Capability = "account-notify" AwayNotify Capability = "away-notify" CapNotify Capability = "cap-notify" + ChgHost Capability = "chghost" EchoMessage Capability = "echo-message" ExtendedJoin Capability = "extended-join" InviteNotify Capability = "invite-notify" @@ -34,6 +35,7 @@ var ( AccountNotify: true, AwayNotify: true, CapNotify: true, + ChgHost: true, EchoMessage: true, ExtendedJoin: true, InviteNotify: true, diff --git a/irc/client.go b/irc/client.go index c0c535ef..1397dd00 100644 --- a/irc/client.go +++ b/irc/client.go @@ -45,6 +45,8 @@ type Client struct { hasQuit bool hops int hostname string + rawHostname string + vhost string idleTimer *time.Timer monitoring map[string]bool nick string @@ -136,7 +138,7 @@ func (client *Client) run() { var msg ircmsg.IrcMessage // Set the hostname for this client - client.hostname = AddrLookupHostname(client.socket.conn.RemoteAddr()) + client.rawHostname = AddrLookupHostname(client.socket.conn.RemoteAddr()) //TODO(dan): Make this a socketreactor from ircbnc for { @@ -313,6 +315,12 @@ func (client *Client) updateNick() { func (client *Client) updateNickMask() { client.updateNick() + if len(client.vhost) > 0 { + client.hostname = client.vhost + } else { + client.hostname = client.rawHostname + } + client.nickMaskString = fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname) nickMaskCasefolded, err := Casefold(client.nickMaskString) diff --git a/irc/config.go b/irc/config.go index 30e9503d..e28ca0d9 100644 --- a/irc/config.go +++ b/irc/config.go @@ -209,6 +209,7 @@ func (conf *Config) OperatorClasses() (*map[string]OperClass, error) { type Oper struct { Class *OperClass WhoisLine string + Vhost string Pass []byte } @@ -224,6 +225,7 @@ func (conf *Config) Operators(oc *map[string]OperClass) (map[string]Oper, error) } oper.Pass = opConf.PasswordBytes() + oper.Vhost = opConf.Vhost class, exists := (*oc)[opConf.Class] if !exists { return nil, fmt.Errorf("Could not load operator [%s] - they use operclass [%s] which does not exist", name, opConf.Class) diff --git a/irc/server.go b/irc/server.go index 63c3bad7..d1eaa635 100644 --- a/irc/server.go +++ b/irc/server.go @@ -904,7 +904,15 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { server.currentOpers[client] = true client.whoisLine = server.operators[name].WhoisLine - //TODO(dan): push out CHGHOST if vhost is applied + // push new vhost if one is set + if len(server.operators[name].Vhost) > 0 { + originalHost := client.nickMaskString + client.vhost = server.operators[name].Vhost + for fClient := range client.Friends(ChgHost) { + fClient.SendFromClient(client, nil, originalHost, "CHGHOST", client.username, client.vhost) + } + client.updateNickMask() + } client.Send(nil, server.name, RPL_YOUREOPER, client.nick, "You are now an IRC operator") //TODO(dan): Should this be sent automagically as part of setting the flag/mode?