mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 21:39:25 +01:00
implement WHOX
This commit is contained in:
parent
f2d0842453
commit
518b21e5aa
@ -1240,6 +1240,7 @@ func (config *Config) generateISupport() (err error) {
|
|||||||
if config.Server.Casemapping == CasemappingPRECIS {
|
if config.Server.Casemapping == CasemappingPRECIS {
|
||||||
isupport.Add("UTF8MAPPING", precisUTF8MappingToken)
|
isupport.Add("UTF8MAPPING", precisUTF8MappingToken)
|
||||||
}
|
}
|
||||||
|
isupport.Add("WHOX", "")
|
||||||
|
|
||||||
err = isupport.RegenerateCachedReply()
|
err = isupport.RegenerateCachedReply()
|
||||||
return
|
return
|
||||||
|
139
irc/handlers.go
139
irc/handlers.go
@ -2775,7 +2775,120 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// WHO [<mask> [o]]
|
const WhoFieldMinimum = int('a') // lowest rune value
|
||||||
|
const WhoFieldMaximum = int('z')
|
||||||
|
|
||||||
|
type WhoFields [WhoFieldMaximum - WhoFieldMinimum + 1]bool
|
||||||
|
|
||||||
|
func (fields *WhoFields) Set(field rune) bool {
|
||||||
|
index := int(field)
|
||||||
|
if WhoFieldMinimum <= index && index <= WhoFieldMaximum {
|
||||||
|
fields[int(field)-WhoFieldMinimum] = true
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (fields *WhoFields) Has(field rune) bool {
|
||||||
|
return fields[int(field)-WhoFieldMinimum]
|
||||||
|
}
|
||||||
|
|
||||||
|
// rplWhoReply returns the WHO(X) reply between one user and another channel/user.
|
||||||
|
// who format:
|
||||||
|
// <channel> <user> <host> <server> <nick> <H|G>[*][~|&|@|%|+][B] :<hopcount> <real name>
|
||||||
|
// whox format:
|
||||||
|
// <type> <channel> <user> <ip> <host> <server> <nick> <H|G>[*][~|&|@|%|+][B] <hops> <idle> <account> <rank> :<real name>
|
||||||
|
func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer, isWhox bool, fields WhoFields, whoType string) {
|
||||||
|
params := []string{client.Nick()}
|
||||||
|
|
||||||
|
details := target.Details()
|
||||||
|
|
||||||
|
if fields.Has('t') {
|
||||||
|
params = append(params, whoType)
|
||||||
|
}
|
||||||
|
if fields.Has('c') {
|
||||||
|
fChannel := "*"
|
||||||
|
if channel != nil {
|
||||||
|
fChannel = channel.name
|
||||||
|
}
|
||||||
|
params = append(params, fChannel)
|
||||||
|
}
|
||||||
|
if fields.Has('u') {
|
||||||
|
params = append(params, details.username)
|
||||||
|
}
|
||||||
|
if fields.Has('i') {
|
||||||
|
fIP := "255.255.255.255"
|
||||||
|
if client.HasMode(modes.Operator) || client == target {
|
||||||
|
// you can only see a target's IP if they're you or you're an oper
|
||||||
|
fIP = target.IPString()
|
||||||
|
}
|
||||||
|
params = append(params, fIP)
|
||||||
|
}
|
||||||
|
if fields.Has('h') {
|
||||||
|
params = append(params, details.hostname)
|
||||||
|
}
|
||||||
|
if fields.Has('s') {
|
||||||
|
params = append(params, target.server.name)
|
||||||
|
}
|
||||||
|
if fields.Has('n') {
|
||||||
|
params = append(params, details.nick)
|
||||||
|
}
|
||||||
|
if fields.Has('f') { // "flags" (away + oper state + channel status prefix + bot)
|
||||||
|
var flags strings.Builder
|
||||||
|
if target.Away() {
|
||||||
|
flags.WriteRune('G') // Gone
|
||||||
|
} else {
|
||||||
|
flags.WriteRune('H') // Here
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.HasMode(modes.Operator) {
|
||||||
|
flags.WriteRune('*')
|
||||||
|
}
|
||||||
|
|
||||||
|
if channel != nil {
|
||||||
|
flags.WriteString(channel.ClientPrefixes(target, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.HasMode(modes.Bot) {
|
||||||
|
flags.WriteRune('B')
|
||||||
|
}
|
||||||
|
|
||||||
|
params = append(params, flags.String())
|
||||||
|
|
||||||
|
}
|
||||||
|
if fields.Has('d') { // server hops from us to target
|
||||||
|
params = append(params, "0")
|
||||||
|
}
|
||||||
|
if fields.Has('l') {
|
||||||
|
params = append(params, fmt.Sprintf("%d", target.IdleSeconds()))
|
||||||
|
}
|
||||||
|
if fields.Has('a') {
|
||||||
|
fAccount := "0"
|
||||||
|
if details.accountName != "*" {
|
||||||
|
// WHOX uses "0" to mean "no account"
|
||||||
|
fAccount = details.accountName
|
||||||
|
}
|
||||||
|
params = append(params, fAccount)
|
||||||
|
}
|
||||||
|
if fields.Has('o') { // target's channel power level
|
||||||
|
//TODO: implement this
|
||||||
|
params = append(params, "0")
|
||||||
|
}
|
||||||
|
if fields.Has('r') {
|
||||||
|
params = append(params, details.realname)
|
||||||
|
}
|
||||||
|
|
||||||
|
numeric := RPL_WHOSPCRPL
|
||||||
|
if !isWhox {
|
||||||
|
numeric = RPL_WHOREPLY
|
||||||
|
// if this isn't WHOX, stick hops + realname at the end
|
||||||
|
params = append(params, "0 "+details.realname)
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.Add(nil, client.server.name, numeric, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WHO <mask> [<filter>%<fields>,<type>]
|
||||||
func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
mask := msg.Params[0]
|
mask := msg.Params[0]
|
||||||
var err error
|
var err error
|
||||||
@ -2793,6 +2906,26 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sFields := "cuhsnf"
|
||||||
|
whoType := "0"
|
||||||
|
isWhox := false
|
||||||
|
if len(msg.Params) > 1 && strings.Contains(msg.Params[1], "%") {
|
||||||
|
isWhox = true
|
||||||
|
whoxData := msg.Params[1]
|
||||||
|
fieldStart := strings.Index(whoxData, "%")
|
||||||
|
sFields = whoxData[fieldStart+1:]
|
||||||
|
|
||||||
|
typeIndex := strings.Index(sFields, ",")
|
||||||
|
if typeIndex > -1 && typeIndex < (len(sFields)-1) { // make sure there's , and a value after it
|
||||||
|
whoType = sFields[typeIndex+1:]
|
||||||
|
sFields = strings.ToLower(sFields[:typeIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fields WhoFields
|
||||||
|
for _, field := range sFields {
|
||||||
|
fields.Set(field)
|
||||||
|
}
|
||||||
|
|
||||||
//TODO(dan): is this used and would I put this param in the Modern doc?
|
//TODO(dan): is this used and would I put this param in the Modern doc?
|
||||||
// if not, can we remove it?
|
// if not, can we remove it?
|
||||||
//var operatorOnly bool
|
//var operatorOnly bool
|
||||||
@ -2810,7 +2943,7 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
if !channel.flags.HasMode(modes.Secret) || isJoined || isOper {
|
if !channel.flags.HasMode(modes.Secret) || isJoined || isOper {
|
||||||
for _, member := range channel.Members() {
|
for _, member := range channel.Members() {
|
||||||
if !member.HasMode(modes.Invisible) || isJoined || isOper {
|
if !member.HasMode(modes.Invisible) || isJoined || isOper {
|
||||||
client.rplWhoReply(channel, member, rb)
|
client.rplWhoReply(channel, member, rb, isWhox, fields, whoType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2838,7 +2971,7 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
|
|||||||
|
|
||||||
for mclient := range server.clients.FindAll(mask) {
|
for mclient := range server.clients.FindAll(mask) {
|
||||||
if isOper || !mclient.HasMode(modes.Invisible) || isFriend(mclient) {
|
if isOper || !mclient.HasMode(modes.Invisible) || isFriend(mclient) {
|
||||||
client.rplWhoReply(nil, mclient, rb)
|
client.rplWhoReply(nil, mclient, rb, isWhox, fields, whoType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ const (
|
|||||||
RPL_VERSION = "351"
|
RPL_VERSION = "351"
|
||||||
RPL_WHOREPLY = "352"
|
RPL_WHOREPLY = "352"
|
||||||
RPL_NAMREPLY = "353"
|
RPL_NAMREPLY = "353"
|
||||||
|
RPL_WHOSPCRPL = "354"
|
||||||
RPL_LINKS = "364"
|
RPL_LINKS = "364"
|
||||||
RPL_ENDOFLINKS = "365"
|
RPL_ENDOFLINKS = "365"
|
||||||
RPL_ENDOFNAMES = "366"
|
RPL_ENDOFNAMES = "366"
|
||||||
|
@ -432,35 +432,6 @@ func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rplWhoReply returns the WHO reply between one user and another channel/user.
|
|
||||||
// <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
|
|
||||||
// :<hopcount> <real name>
|
|
||||||
func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer) {
|
|
||||||
channelName := "*"
|
|
||||||
flags := ""
|
|
||||||
|
|
||||||
if target.Away() {
|
|
||||||
flags = "G"
|
|
||||||
} else {
|
|
||||||
flags = "H"
|
|
||||||
}
|
|
||||||
if target.HasMode(modes.Operator) {
|
|
||||||
flags += "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
if channel != nil {
|
|
||||||
// TODO is this right?
|
|
||||||
flags += channel.ClientPrefixes(target, rb.session.capabilities.Has(caps.MultiPrefix))
|
|
||||||
channelName = channel.name
|
|
||||||
}
|
|
||||||
if target.HasMode(modes.Bot) {
|
|
||||||
flags += "B"
|
|
||||||
}
|
|
||||||
details := target.Details()
|
|
||||||
// hardcode a hopcount of 0 for now
|
|
||||||
rb.Add(nil, client.server.name, RPL_WHOREPLY, client.Nick(), channelName, details.username, details.hostname, client.server.name, details.nick, flags, "0 "+details.realname)
|
|
||||||
}
|
|
||||||
|
|
||||||
// rehash reloads the config and applies the changes from the config file.
|
// rehash reloads the config and applies the changes from the config file.
|
||||||
func (server *Server) rehash() error {
|
func (server *Server) rehash() error {
|
||||||
server.logger.Info("server", "Attempting rehash")
|
server.logger.Info("server", "Attempting rehash")
|
||||||
|
Loading…
Reference in New Issue
Block a user