Browse Source

help: Add new /HELP command

tags/v0.2.0
Daniel Oaks 7 years ago
parent
commit
7b50f64d7e
4 changed files with 340 additions and 0 deletions
  1. 1
    0
      CHANGELOG.md
  2. 4
    0
      irc/commands.go
  3. 331
    0
      irc/help.go
  4. 4
    0
      irc/numerics.go

+ 1
- 0
CHANGELOG.md View File

@@ -12,6 +12,7 @@ Improved compatibility, more features, etc.
12 12
 ### Security
13 13
 
14 14
 ### Added
15
+* Add integrated help.
15 16
 * Support for IRCv3 capability [`account-notify`](http://ircv3.net/specs/extensions/account-notify-3.1.html)
16 17
 
17 18
 ### Changed

+ 4
- 0
irc/commands.go View File

@@ -67,6 +67,10 @@ var Commands = map[string]Command{
67 67
 		handler:   debugHandler,
68 68
 		minParams: 1,
69 69
 	},
70
+	"HELP": {
71
+		handler:   helpHandler,
72
+		minParams: 0,
73
+	},
70 74
 	"INVITE": {
71 75
 		handler:   inviteHandler,
72 76
 		minParams: 2,

+ 331
- 0
irc/help.go View File

@@ -0,0 +1,331 @@
1
+// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
2
+// released under the MIT license
3
+
4
+package irc
5
+
6
+import (
7
+	"strings"
8
+
9
+	"github.com/DanielOaks/girc-go/ircmsg"
10
+)
11
+
12
+// HelpEntry represents an entry in the Help map.
13
+type HelpEntry struct {
14
+	oper bool
15
+	text string
16
+}
17
+
18
+// used for duplicates
19
+var (
20
+	cmodeHelpText = `== Channel Modes ==
21
+        
22
+Oragono supports the following channel modes:
23
+
24
+= Type A - list modes =
25
+
26
+  +b  |  Client masks that are banned from the channel.
27
+  +e  |  Client masks that are exempted from bans.
28
+  +I  |  Client masks that are exempted from the invite-only flag.
29
+
30
+= Type C - setting modes with a parameter =
31
+
32
+  +l  |  Client join limit for the channel.
33
+  +k  |  Key required when joining the channel.
34
+
35
+= Type D - flag modes =
36
+
37
+  +i  |  Invite-only mode, only invited clients can join the channel.
38
+  +m  |  Moderated mode, only priviledged clients can talk on the channel.
39
+  +n  |  No-outside-messages mode, only users that are on the channel can send the channel messages.
40
+  +t  |  Only channel opers can modify the topic.
41
+  +s  |  Secret mode, channel won't show up in /LIST or whois replies.  
42
+
43
+= Prefixes =
44
+
45
+  +q (~)  |  Founder channel mode.
46
+  +a (&)  |  Admin channel mode.
47
+  +o (@)  |  Operator channel mode.
48
+  +h (%)  |  Halfop channel mode.
49
+  +v (+)  |  Voice channel mode.`
50
+	umodeHelpText = `== User Modes ==
51
+        
52
+Oragono supports the following user modes:
53
+
54
+  +a  |  User is marked as being away. This mode is set with the /AWAY command.
55
+  +i  |  User is marked as invisible (their channels are hidden from whois replies).
56
+  +o  |  User is an IRC operator.
57
+  +Z  |  User is connected via TLS.`
58
+)
59
+
60
+// Help contains the help strings distributed with the IRCd.
61
+var Help = map[string]HelpEntry{
62
+	// Commands
63
+	"authenticate": {
64
+		text: `AUTHENTICATE
65
+        
66
+Used during SASL authentication. See the IRCv3 specs for more info:
67
+http://ircv3.net/specs/extensions/sasl-3.1.html`,
68
+	},
69
+	"away": {
70
+		text: `AWAY [message]
71
+
72
+If [message] is sent, marks you away. If [message] is not sent, marks you no
73
+longer away.`,
74
+	},
75
+	"cap": {
76
+		text: `CAP <subcommand> [:<capabilities>]
77
+        
78
+Used in capability negotiation. See the IRCv3 specs for more info:
79
+http://ircv3.net/specs/core/capability-negotiation-3.1.html
80
+http://ircv3.net/specs/core/capability-negotiation-3.2.html`,
81
+	},
82
+	"debug": {
83
+		oper: true,
84
+		text: `DEBUG <option>
85
+        
86
+Prints debug information about the IRCd. <option> can be one of:
87
+
88
+* GCSTATS: Garbage control statistics.
89
+* NUMGOROUTINE: Number of goroutines in use.
90
+* STARTCPUPROFILE: Starts the CPU profiler.
91
+* STOPCPUPROFILE: Stops the CPU profiler.
92
+* PROFILEHEAP: Writes out the CPU profiler info.`,
93
+	},
94
+	"invite": {
95
+		text: `INVITE <nickname> <channel>
96
+
97
+Invites the given user to the given channel, so long as you have the
98
+appropriate channel privs.`,
99
+	},
100
+	"ison": {
101
+		text: `ISON <nickname>{ <nickname>}
102
+        
103
+Returns whether the given nicks exist on the network.`,
104
+	},
105
+	"join": {
106
+		text: `JOIN <channel>{,<channel>} [<key>{,<key>}]
107
+JOIN 0
108
+
109
+Joins the given channels with the matching keys, or if the only param is "0"
110
+parts all channels instead.`,
111
+	},
112
+	"kick": {
113
+		text: `KICK <channel> <user> [reason]
114
+        
115
+Removes the user from the given channel, so long as you have the appropriate
116
+channel privs.`,
117
+	},
118
+	"kill": {
119
+		oper: true,
120
+		text: `KILL <nickname> [reason]
121
+        
122
+Removes the given user from the network, showing them the reason if it is
123
+supplied.`,
124
+	},
125
+	"list": {
126
+		text: `LIST [<channel>{,<channel>}] [<elistcond>{,<elistcond>}]
127
+        
128
+Shows information on the given channels (or if none are given, then on all
129
+channels). <elistcond>s modify how the channels are selected.`,
130
+		//TODO(dan): Explain <elistcond>s in more specific detail
131
+	},
132
+	"mode": {
133
+		text: `MODE <target> [<modestring> [<mode arguments>...]]
134
+        
135
+Sets and removes modes from the given target. For more specific information on
136
+mode characters, see the help for "cmode" and "umode".`,
137
+	},
138
+	"motd": {
139
+		text: `MOTD [server]
140
+        
141
+Returns the message of the day for this, or the given, server.`,
142
+	},
143
+	"names": {
144
+		text: `NAMES [<channel>{,<channel>}]
145
+        
146
+Views the clients joined to a channel and their channel membership prefixes. To
147
+view the channel membership prefixes supported by this server, see the help for
148
+"PREFIX".`,
149
+	},
150
+	"nick": {
151
+		text: `NICK <newnick>
152
+        
153
+Sets your nickname to the new given one.`,
154
+	},
155
+	"notice": {
156
+		text: `NOTICE <target>{,<target>} <text to be sent>
157
+        
158
+Sends the text to the given targets as a NOTICE.`,
159
+	},
160
+	"oper": {
161
+		text: `OPER <name> <password>
162
+        
163
+If the correct details are given, gives you IRCop privs.`,
164
+	},
165
+	"part": {
166
+		text: `PART <channel>{,<channel>} [reason]
167
+
168
+Leaves the given channels and shows people the given reason.`,
169
+	},
170
+	"pass": {
171
+		text: `PASS <password>
172
+        
173
+When the server requires a connection password to join, used to send us the
174
+password.`,
175
+	},
176
+	"ping": {
177
+		text: `PING <args>...
178
+        
179
+Requests a PONG. Used to check link connectivity.`,
180
+	},
181
+	"pong": {
182
+		text: `PONG <args>...
183
+        
184
+Replies to a PING. Used to check link connectivity.`,
185
+	},
186
+	"privmsg": {
187
+		text: `PRIVMSG <target>{,<target>} <text to be sent>
188
+        
189
+Sends the text to the given targets as a PRIVMSG.`,
190
+	},
191
+	"proxy": {
192
+		oper: true, // not really, but it's restricted anyways
193
+		text: `PROXY TCP4/6 <sourceip> <destip> <sourceport> <destport>
194
+        
195
+Used by haproxy's PROXY protocol, to allow for alternate TLS support:
196
+http://www.haproxy.org/download/1.7/doc/proxy-protocol.txt`,
197
+	},
198
+	"sanick": {
199
+		oper: true,
200
+		text: `SANICK <currentnick> <newnick>
201
+
202
+Gives the given user a new nickname.`,
203
+	},
204
+	"quit": {
205
+		text: `QUIT [reason]
206
+        
207
+Indicates that you're leaving the server, and shows everyone the given reason.`,
208
+	},
209
+	"reg": {
210
+		text: `REG CREATE <accountname> [callback_namespace:]<callback> [cred_type] :<credential>
211
+REG VERIFY <accountname> <auth_code>
212
+
213
+Used in account registration. See the relevant specs for more info:
214
+https://github.com/DanielOaks/ircv3-specifications/blob/register-and-verify/extensions/reg-core-3.3.md`,
215
+	},
216
+	"time": {
217
+		text: `TIME [server]
218
+        
219
+Shows the time of the current, or the given, server.`,
220
+	},
221
+	"topic": {
222
+		text: `TOPIC <channel> [topic]
223
+        
224
+If [topic] is given, sets the topic in the channel to that. If [topic] is not
225
+given, views the current topic on the channel.`,
226
+	},
227
+	"user": {
228
+		text: `USER <username> 0 * <realname>
229
+        
230
+Used in connection registration, sets your username and realname to the given
231
+values (though your username may also be looked up with Ident).`,
232
+	},
233
+	"version": {
234
+		text: `VERSION [server]
235
+        
236
+Views the version of software and the RPL_ISUPPORT tokens for the given server.`,
237
+	},
238
+	"who": {
239
+		text: `WHO <name> [o]
240
+
241
+Returns information for the given user.`,
242
+	},
243
+	"whois": {
244
+		text: `WHOIS <client>{,<client>}
245
+        
246
+Returns information for the given user(s).`,
247
+	},
248
+	"whowas": {
249
+		text: `WHOWAS <nickname>
250
+        
251
+Returns historical information on the last user with the given nickname.`,
252
+	},
253
+
254
+	// Informational
255
+	"cmode": {
256
+		text: cmodeHelpText,
257
+	},
258
+	"cmodes": {
259
+		text: cmodeHelpText,
260
+	},
261
+	"umode": {
262
+		text: umodeHelpText,
263
+	},
264
+	"umodes": {
265
+		text: umodeHelpText,
266
+	},
267
+
268
+	// RPL_ISUPPORT
269
+	"casemapping": {
270
+		text: `RPL_ISUPPORT CASEMAPPING
271
+        
272
+Oragono supports an experimental unicode casemapping designed for extended
273
+Unicode support. This casemapping is based off RFC 7700 and the draft rfc7700
274
+casemapping spec here:
275
+https://github.com/DanielOaks/ircv3-specifications/blob/master%2Brfc7700/documentation/rfc7700.md`,
276
+	},
277
+	"prefix": {
278
+		text: `RPL_ISUPPORT PREFIX
279
+
280
+Oragono supports the following channel membership prefixes:
281
+
282
+  +q (~)  |  Founder channel mode.
283
+  +a (&)  |  Admin channel mode.
284
+  +o (@)  |  Operator channel mode.
285
+  +h (%)  |  Halfop channel mode.
286
+  +v (+)  |  Voice channel mode.`,
287
+	},
288
+}
289
+
290
+// sendHelp sends the client help of the given string.
291
+func (client *Client) sendHelp(name string, text string) {
292
+	splitName := strings.Split(name, " ")
293
+	textLines := strings.Split(text, "\n")
294
+
295
+	for i, line := range textLines {
296
+		args := splitName
297
+		args = append(args, line)
298
+		if i == 0 {
299
+			client.Send(nil, client.server.name, RPL_HELPSTART, args...)
300
+		} else {
301
+			client.Send(nil, client.server.name, RPL_HELPTXT, args...)
302
+		}
303
+	}
304
+	args := splitName
305
+	args = append(args, "End of /HELP")
306
+	client.Send(nil, client.server.name, RPL_ENDOFHELP, args...)
307
+}
308
+
309
+// helpHandler returns the appropriate help for the given query.
310
+func helpHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
311
+	argument := strings.ToLower(strings.TrimSpace(strings.Join(msg.Params, " ")))
312
+
313
+	if len(argument) < 1 {
314
+		client.sendHelp("HELP", `HELP <argument>
315
+        
316
+Get an explanation of <argument>.`)
317
+		return false
318
+	}
319
+
320
+	helpHandler, exists := Help[argument]
321
+
322
+	if exists && (!client.flags[Operator] || (helpHandler.oper && client.flags[Operator])) {
323
+		client.sendHelp(strings.ToUpper(argument), helpHandler.text)
324
+	} else {
325
+		args := msg.Params
326
+		args = append(args, "Help not found")
327
+		client.Send(nil, server.name, ERR_HELPNOTFOUND, args...)
328
+	}
329
+
330
+	return false
331
+}

+ 4
- 0
irc/numerics.go View File

@@ -149,6 +149,10 @@ const (
149 149
 	ERR_NOOPERHOST                  = "491"
150 150
 	ERR_UMODEUNKNOWNFLAG            = "501"
151 151
 	ERR_USERSDONTMATCH              = "502"
152
+	ERR_HELPNOTFOUND                = "524"
153
+	RPL_HELPSTART                   = "704"
154
+	RPL_HELPTXT                     = "705"
155
+	RPL_ENDOFHELP                   = "706"
152 156
 	RPL_LOGGEDIN                    = "900"
153 157
 	RPL_LOGGEDOUT                   = "901"
154 158
 	ERR_NICKLOCKED                  = "902"

Loading…
Cancel
Save