From 825cdab67d23c8d963612cb09801a76a10a406b7 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Fri, 2 Dec 2022 07:04:19 -0500 Subject: [PATCH] fix #1850 Add WHO responses for services --- irc/handlers.go | 66 ++++++++++++++++++++++++++++++++++++++++++++----- irc/services.go | 18 ++++++++------ 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/irc/handlers.go b/irc/handlers.go index 156bee8b..bb5dc1ba 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -1892,7 +1892,7 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon // get the correct capitalization of a nick (if it's online), otherwise return "" func (server *Server) getCurrentNick(nick string) (result string) { - if service, isService := OragonoServices[strings.ToLower(nick)]; isService { + if service, isService := ErgoServices[strings.ToLower(nick)]; isService { return service.Name } else if iclient := server.clients.Get(nick); iclient != nil { return iclient.Nick() @@ -2277,7 +2277,7 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi } } else { lowercaseTarget := strings.ToLower(target) - service, isService := OragonoServices[lowercaseTarget] + service, isService := ErgoServices[lowercaseTarget] _, isZNC := zncHandlers[lowercaseTarget] if isService || isZNC { @@ -3427,6 +3427,59 @@ func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *Response rb.Add(nil, client.server.name, numeric, params...) } +func serviceWhoReply(client *Client, service *ircService, rb *ResponseBuffer, isWhox bool, fields whoxFields, whoType string) { + params := []string{client.Nick()} + + if fields.Has('t') { + params = append(params, whoType) + } + if fields.Has('c') { + params = append(params, "*") + } + if fields.Has('u') { + params = append(params, service.Name) + } + if fields.Has('i') { + params = append(params, "127.0.0.1") + } + if fields.Has('h') { + params = append(params, "localhost") + } + if fields.Has('s') { + params = append(params, client.server.name) + } + if fields.Has('n') { + params = append(params, service.Name) + } + if fields.Has('f') { // "flags" (away + oper state + channel status prefix + bot) + params = append(params, "H") + } + if fields.Has('d') { // server hops from us to target + params = append(params, "0") + } + if fields.Has('l') { // idle seconds + params = append(params, "0") + } + if fields.Has('a') { // account, services are considered not to have one + params = append(params, "0") + } + if fields.Has('o') { // channel oplevel, not implemented + params = append(params, "*") + } + if fields.Has('r') { + params = append(params, service.Realname(client)) + } + + numeric := RPL_WHOSPCRPL + if !isWhox { + numeric = RPL_WHOREPLY + // if this isn't WHOX, stick hops + realname at the end + params = append(params, "0 "+service.Realname(client)) + } + + rb.Add(nil, client.server.name, numeric, params...) +} + // WHO [%,] func whoHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool { origMask := utils.SafeErrorParam(msg.Params[0]) @@ -3519,9 +3572,10 @@ func whoHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response } } } else if isBareNick { - mclient := server.clients.Get(mask) - if mclient != nil { + if mclient := server.clients.Get(mask); mclient != nil { client.rplWhoReply(nil, mclient, rb, canSeeIPs, oper != nil, includeRFlag, isWhox, fields, whoType) + } else if service, ok := ErgoServices[strings.ToLower(mask)]; ok { + serviceWhoReply(client, service, rb, isWhox, fields, whoType) } } else { // Construct set of channels the client is in. @@ -3571,7 +3625,7 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon handleService := func(nick string) bool { cfnick, _ := CasefoldName(nick) - service, ok := OragonoServices[cfnick] + service, ok := ErgoServices[cfnick] hostname := "localhost" config := server.Config() if config.Server.OverrideServicesHostname != "" { @@ -3581,7 +3635,7 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon return false } clientNick := client.Nick() - rb.Add(nil, client.server.name, RPL_WHOISUSER, clientNick, service.Name, service.Name, hostname, "*", fmt.Sprintf(client.t("Network service, for more info /msg %s HELP"), service.Name)) + rb.Add(nil, client.server.name, RPL_WHOISUSER, clientNick, service.Name, service.Name, hostname, "*", service.Realname(client)) // #1080: rb.Add(nil, client.server.name, RPL_WHOISOPERATOR, clientNick, service.Name, client.t("is a network service")) // hehe diff --git a/irc/services.go b/irc/services.go index 10a50fa3..7bd9c5f1 100644 --- a/irc/services.go +++ b/irc/services.go @@ -26,6 +26,10 @@ type ircService struct { HelpBanner string } +func (service *ircService) Realname(client *Client) string { + return fmt.Sprintf(client.t("Network service, for more info /msg %s HELP"), service.Name) +} + // defines a command associated with a service, e.g., NICKSERV IDENTIFY type serviceCommand struct { aliasOf string // marks this command as an alias of another @@ -92,7 +96,7 @@ var ( ) // all services, by lowercase name -var OragonoServices = map[string]*ircService{ +var ErgoServices = map[string]*ircService{ "nickserv": nickservService, "chanserv": chanservService, "hostserv": hostservService, @@ -105,7 +109,7 @@ func (service *ircService) Notice(rb *ResponseBuffer, text string) { // all service commands at the protocol level, by uppercase command name // e.g., NICKSERV, NS -var oragonoServicesByCommandAlias map[string]*ircService +var ergoServicesByCommandAlias map[string]*ircService // special-cased command shared by all services var servHelpCmd serviceCommand = serviceCommand{ @@ -117,7 +121,7 @@ HELP returns information on the given command.`, // generic handler for IRC commands like `/NICKSERV INFO` func serviceCmdHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool { - service, ok := oragonoServicesByCommandAlias[msg.Command] + service, ok := ergoServicesByCommandAlias[msg.Command] if !ok { server.logger.Warning("internal", "can't handle unrecognized service", msg.Command) return false @@ -323,7 +327,7 @@ func overrideServicePrefixes(hostname string) error { if !utils.IsHostname(hostname) { return fmt.Errorf("`%s` is an invalid services hostname", hostname) } - for _, serv := range OragonoServices { + for _, serv := range ErgoServices { serv.prefix = fmt.Sprintf("%s!%s@%s", serv.Name, serv.Name, hostname) } return nil @@ -332,9 +336,9 @@ func overrideServicePrefixes(hostname string) error { func initializeServices() { // this modifies the global Commands map, // so it must be called from irc/commands.go's init() - oragonoServicesByCommandAlias = make(map[string]*ircService) + ergoServicesByCommandAlias = make(map[string]*ircService) - for serviceName, service := range OragonoServices { + for serviceName, service := range ErgoServices { service.prefix = fmt.Sprintf("%s!%s@localhost", service.Name, service.Name) // make `/MSG ServiceName HELP` work correctly @@ -349,7 +353,7 @@ func initializeServices() { ircCmdDef.handler = serviceCmdHandler for _, ircCmd := range service.CommandAliases { Commands[ircCmd] = ircCmdDef - oragonoServicesByCommandAlias[ircCmd] = service + ergoServicesByCommandAlias[ircCmd] = service Help[strings.ToLower(ircCmd)] = HelpEntry{ textGenerator: makeServiceHelpTextGenerator(ircCmd, service.HelpBanner), }