mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
help: Add new /HELP command
This commit is contained in:
parent
da6f350563
commit
7b50f64d7e
@ -12,6 +12,7 @@ Improved compatibility, more features, etc.
|
||||
### Security
|
||||
|
||||
### Added
|
||||
* Add integrated help.
|
||||
* Support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html)
|
||||
|
||||
### Changed
|
||||
|
@ -67,6 +67,10 @@ var Commands = map[string]Command{
|
||||
handler: debugHandler,
|
||||
minParams: 1,
|
||||
},
|
||||
"HELP": {
|
||||
handler: helpHandler,
|
||||
minParams: 0,
|
||||
},
|
||||
"INVITE": {
|
||||
handler: inviteHandler,
|
||||
minParams: 2,
|
||||
|
331
irc/help.go
Normal file
331
irc/help.go
Normal file
@ -0,0 +1,331 @@
|
||||
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
||||
// released under the MIT license
|
||||
|
||||
package irc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/DanielOaks/girc-go/ircmsg"
|
||||
)
|
||||
|
||||
// HelpEntry represents an entry in the Help map.
|
||||
type HelpEntry struct {
|
||||
oper bool
|
||||
text string
|
||||
}
|
||||
|
||||
// used for duplicates
|
||||
var (
|
||||
cmodeHelpText = `== Channel Modes ==
|
||||
|
||||
Oragono supports the following channel modes:
|
||||
|
||||
= Type A - list modes =
|
||||
|
||||
+b | Client masks that are banned from the channel.
|
||||
+e | Client masks that are exempted from bans.
|
||||
+I | Client masks that are exempted from the invite-only flag.
|
||||
|
||||
= Type C - setting modes with a parameter =
|
||||
|
||||
+l | Client join limit for the channel.
|
||||
+k | Key required when joining the channel.
|
||||
|
||||
= Type D - flag modes =
|
||||
|
||||
+i | Invite-only mode, only invited clients can join the channel.
|
||||
+m | Moderated mode, only priviledged clients can talk on the channel.
|
||||
+n | No-outside-messages mode, only users that are on the channel can send the channel messages.
|
||||
+t | Only channel opers can modify the topic.
|
||||
+s | Secret mode, channel won't show up in /LIST or whois replies.
|
||||
|
||||
= Prefixes =
|
||||
|
||||
+q (~) | Founder channel mode.
|
||||
+a (&) | Admin channel mode.
|
||||
+o (@) | Operator channel mode.
|
||||
+h (%) | Halfop channel mode.
|
||||
+v (+) | Voice channel mode.`
|
||||
umodeHelpText = `== User Modes ==
|
||||
|
||||
Oragono supports the following user modes:
|
||||
|
||||
+a | User is marked as being away. This mode is set with the /AWAY command.
|
||||
+i | User is marked as invisible (their channels are hidden from whois replies).
|
||||
+o | User is an IRC operator.
|
||||
+Z | User is connected via TLS.`
|
||||
)
|
||||
|
||||
// Help contains the help strings distributed with the IRCd.
|
||||
var Help = map[string]HelpEntry{
|
||||
// Commands
|
||||
"authenticate": {
|
||||
text: `AUTHENTICATE
|
||||
|
||||
Used during SASL authentication. See the IRCv3 specs for more info:
|
||||
http://ircv3.net/specs/extensions/sasl-3.1.html`,
|
||||
},
|
||||
"away": {
|
||||
text: `AWAY [message]
|
||||
|
||||
If [message] is sent, marks you away. If [message] is not sent, marks you no
|
||||
longer away.`,
|
||||
},
|
||||
"cap": {
|
||||
text: `CAP <subcommand> [:<capabilities>]
|
||||
|
||||
Used in capability negotiation. See the IRCv3 specs for more info:
|
||||
http://ircv3.net/specs/core/capability-negotiation-3.1.html
|
||||
http://ircv3.net/specs/core/capability-negotiation-3.2.html`,
|
||||
},
|
||||
"debug": {
|
||||
oper: true,
|
||||
text: `DEBUG <option>
|
||||
|
||||
Prints debug information about the IRCd. <option> can be one of:
|
||||
|
||||
* GCSTATS: Garbage control statistics.
|
||||
* NUMGOROUTINE: Number of goroutines in use.
|
||||
* STARTCPUPROFILE: Starts the CPU profiler.
|
||||
* STOPCPUPROFILE: Stops the CPU profiler.
|
||||
* PROFILEHEAP: Writes out the CPU profiler info.`,
|
||||
},
|
||||
"invite": {
|
||||
text: `INVITE <nickname> <channel>
|
||||
|
||||
Invites the given user to the given channel, so long as you have the
|
||||
appropriate channel privs.`,
|
||||
},
|
||||
"ison": {
|
||||
text: `ISON <nickname>{ <nickname>}
|
||||
|
||||
Returns whether the given nicks exist on the network.`,
|
||||
},
|
||||
"join": {
|
||||
text: `JOIN <channel>{,<channel>} [<key>{,<key>}]
|
||||
JOIN 0
|
||||
|
||||
Joins the given channels with the matching keys, or if the only param is "0"
|
||||
parts all channels instead.`,
|
||||
},
|
||||
"kick": {
|
||||
text: `KICK <channel> <user> [reason]
|
||||
|
||||
Removes the user from the given channel, so long as you have the appropriate
|
||||
channel privs.`,
|
||||
},
|
||||
"kill": {
|
||||
oper: true,
|
||||
text: `KILL <nickname> [reason]
|
||||
|
||||
Removes the given user from the network, showing them the reason if it is
|
||||
supplied.`,
|
||||
},
|
||||
"list": {
|
||||
text: `LIST [<channel>{,<channel>}] [<elistcond>{,<elistcond>}]
|
||||
|
||||
Shows information on the given channels (or if none are given, then on all
|
||||
channels). <elistcond>s modify how the channels are selected.`,
|
||||
//TODO(dan): Explain <elistcond>s in more specific detail
|
||||
},
|
||||
"mode": {
|
||||
text: `MODE <target> [<modestring> [<mode arguments>...]]
|
||||
|
||||
Sets and removes modes from the given target. For more specific information on
|
||||
mode characters, see the help for "cmode" and "umode".`,
|
||||
},
|
||||
"motd": {
|
||||
text: `MOTD [server]
|
||||
|
||||
Returns the message of the day for this, or the given, server.`,
|
||||
},
|
||||
"names": {
|
||||
text: `NAMES [<channel>{,<channel>}]
|
||||
|
||||
Views the clients joined to a channel and their channel membership prefixes. To
|
||||
view the channel membership prefixes supported by this server, see the help for
|
||||
"PREFIX".`,
|
||||
},
|
||||
"nick": {
|
||||
text: `NICK <newnick>
|
||||
|
||||
Sets your nickname to the new given one.`,
|
||||
},
|
||||
"notice": {
|
||||
text: `NOTICE <target>{,<target>} <text to be sent>
|
||||
|
||||
Sends the text to the given targets as a NOTICE.`,
|
||||
},
|
||||
"oper": {
|
||||
text: `OPER <name> <password>
|
||||
|
||||
If the correct details are given, gives you IRCop privs.`,
|
||||
},
|
||||
"part": {
|
||||
text: `PART <channel>{,<channel>} [reason]
|
||||
|
||||
Leaves the given channels and shows people the given reason.`,
|
||||
},
|
||||
"pass": {
|
||||
text: `PASS <password>
|
||||
|
||||
When the server requires a connection password to join, used to send us the
|
||||
password.`,
|
||||
},
|
||||
"ping": {
|
||||
text: `PING <args>...
|
||||
|
||||
Requests a PONG. Used to check link connectivity.`,
|
||||
},
|
||||
"pong": {
|
||||
text: `PONG <args>...
|
||||
|
||||
Replies to a PING. Used to check link connectivity.`,
|
||||
},
|
||||
"privmsg": {
|
||||
text: `PRIVMSG <target>{,<target>} <text to be sent>
|
||||
|
||||
Sends the text to the given targets as a PRIVMSG.`,
|
||||
},
|
||||
"proxy": {
|
||||
oper: true, // not really, but it's restricted anyways
|
||||
text: `PROXY TCP4/6 <sourceip> <destip> <sourceport> <destport>
|
||||
|
||||
Used by haproxy's PROXY protocol, to allow for alternate TLS support:
|
||||
http://www.haproxy.org/download/1.7/doc/proxy-protocol.txt`,
|
||||
},
|
||||
"sanick": {
|
||||
oper: true,
|
||||
text: `SANICK <currentnick> <newnick>
|
||||
|
||||
Gives the given user a new nickname.`,
|
||||
},
|
||||
"quit": {
|
||||
text: `QUIT [reason]
|
||||
|
||||
Indicates that you're leaving the server, and shows everyone the given reason.`,
|
||||
},
|
||||
"reg": {
|
||||
text: `REG CREATE <accountname> [callback_namespace:]<callback> [cred_type] :<credential>
|
||||
REG VERIFY <accountname> <auth_code>
|
||||
|
||||
Used in account registration. See the relevant specs for more info:
|
||||
https://github.com/DanielOaks/ircv3-specifications/blob/register-and-verify/extensions/reg-core-3.3.md`,
|
||||
},
|
||||
"time": {
|
||||
text: `TIME [server]
|
||||
|
||||
Shows the time of the current, or the given, server.`,
|
||||
},
|
||||
"topic": {
|
||||
text: `TOPIC <channel> [topic]
|
||||
|
||||
If [topic] is given, sets the topic in the channel to that. If [topic] is not
|
||||
given, views the current topic on the channel.`,
|
||||
},
|
||||
"user": {
|
||||
text: `USER <username> 0 * <realname>
|
||||
|
||||
Used in connection registration, sets your username and realname to the given
|
||||
values (though your username may also be looked up with Ident).`,
|
||||
},
|
||||
"version": {
|
||||
text: `VERSION [server]
|
||||
|
||||
Views the version of software and the RPL_ISUPPORT tokens for the given server.`,
|
||||
},
|
||||
"who": {
|
||||
text: `WHO <name> [o]
|
||||
|
||||
Returns information for the given user.`,
|
||||
},
|
||||
"whois": {
|
||||
text: `WHOIS <client>{,<client>}
|
||||
|
||||
Returns information for the given user(s).`,
|
||||
},
|
||||
"whowas": {
|
||||
text: `WHOWAS <nickname>
|
||||
|
||||
Returns historical information on the last user with the given nickname.`,
|
||||
},
|
||||
|
||||
// Informational
|
||||
"cmode": {
|
||||
text: cmodeHelpText,
|
||||
},
|
||||
"cmodes": {
|
||||
text: cmodeHelpText,
|
||||
},
|
||||
"umode": {
|
||||
text: umodeHelpText,
|
||||
},
|
||||
"umodes": {
|
||||
text: umodeHelpText,
|
||||
},
|
||||
|
||||
// RPL_ISUPPORT
|
||||
"casemapping": {
|
||||
text: `RPL_ISUPPORT CASEMAPPING
|
||||
|
||||
Oragono supports an experimental unicode casemapping designed for extended
|
||||
Unicode support. This casemapping is based off RFC 7700 and the draft rfc7700
|
||||
casemapping spec here:
|
||||
https://github.com/DanielOaks/ircv3-specifications/blob/master%2Brfc7700/documentation/rfc7700.md`,
|
||||
},
|
||||
"prefix": {
|
||||
text: `RPL_ISUPPORT PREFIX
|
||||
|
||||
Oragono supports the following channel membership prefixes:
|
||||
|
||||
+q (~) | Founder channel mode.
|
||||
+a (&) | Admin channel mode.
|
||||
+o (@) | Operator channel mode.
|
||||
+h (%) | Halfop channel mode.
|
||||
+v (+) | Voice channel mode.`,
|
||||
},
|
||||
}
|
||||
|
||||
// sendHelp sends the client help of the given string.
|
||||
func (client *Client) sendHelp(name string, text string) {
|
||||
splitName := strings.Split(name, " ")
|
||||
textLines := strings.Split(text, "\n")
|
||||
|
||||
for i, line := range textLines {
|
||||
args := splitName
|
||||
args = append(args, line)
|
||||
if i == 0 {
|
||||
client.Send(nil, client.server.name, RPL_HELPSTART, args...)
|
||||
} else {
|
||||
client.Send(nil, client.server.name, RPL_HELPTXT, args...)
|
||||
}
|
||||
}
|
||||
args := splitName
|
||||
args = append(args, "End of /HELP")
|
||||
client.Send(nil, client.server.name, RPL_ENDOFHELP, args...)
|
||||
}
|
||||
|
||||
// helpHandler returns the appropriate help for the given query.
|
||||
func helpHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
argument := strings.ToLower(strings.TrimSpace(strings.Join(msg.Params, " ")))
|
||||
|
||||
if len(argument) < 1 {
|
||||
client.sendHelp("HELP", `HELP <argument>
|
||||
|
||||
Get an explanation of <argument>.`)
|
||||
return false
|
||||
}
|
||||
|
||||
helpHandler, exists := Help[argument]
|
||||
|
||||
if exists && (!client.flags[Operator] || (helpHandler.oper && client.flags[Operator])) {
|
||||
client.sendHelp(strings.ToUpper(argument), helpHandler.text)
|
||||
} else {
|
||||
args := msg.Params
|
||||
args = append(args, "Help not found")
|
||||
client.Send(nil, server.name, ERR_HELPNOTFOUND, args...)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -149,6 +149,10 @@ const (
|
||||
ERR_NOOPERHOST = "491"
|
||||
ERR_UMODEUNKNOWNFLAG = "501"
|
||||
ERR_USERSDONTMATCH = "502"
|
||||
ERR_HELPNOTFOUND = "524"
|
||||
RPL_HELPSTART = "704"
|
||||
RPL_HELPTXT = "705"
|
||||
RPL_ENDOFHELP = "706"
|
||||
RPL_LOGGEDIN = "900"
|
||||
RPL_LOGGEDOUT = "901"
|
||||
ERR_NICKLOCKED = "902"
|
||||
|
Loading…
Reference in New Issue
Block a user