]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/rfc2812.rb
cc7fd7e797e24589faa6e0068723605fd59851a7
[user/henk/code/ruby/rbot.git] / lib / rbot / rfc2812.rb
1 module Irc
2   # RFC 2812   Internet Relay Chat: Client Protocol
3   #
4   RPL_WELCOME=001
5   # "Welcome to the Internet Relay Network
6   # <nick>!<user>@<host>"
7   RPL_YOURHOST=002
8   # "Your host is <servername>, running version <ver>"
9   RPL_CREATED=003
10   # "This server was created <date>"
11   RPL_MYINFO=004
12   # "<servername> <version> <available user modes>
13   # <available channel modes>"
14   #
15   # - The server sends Replies 001 to 004 to a user upon
16   # successful registration.
17   #
18   # RPL_BOUNCE=005
19   # # "Try server <server name>, port <port number>"
20   RPL_ISUPPORT=005
21   # "005 nick PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
22   #
23   # - Sent by the server to a user to suggest an alternative
24   # server.  This is often used when the connection is
25   # refused because the server is already full.
26   #
27   RPL_USERHOST=302
28   # ":*1<reply> *( " " <reply> )"
29   #
30   # - Reply format used by USERHOST to list replies to
31   # the query list.  The reply string is composed as
32   # follows:
33   #
34   # reply = nickname [ "*" ] "=" ( "+" / "-" ) hostname
35   #
36   # The '*' indicates whether the client has registered
37   # as an Operator.  The '-' or '+' characters represent
38   # whether the client has set an AWAY message or not
39   # respectively.
40   #
41   RPL_ISON=303
42   # ":*1<nick> *( " " <nick> )"
43   #
44   # - Reply format used by ISON to list replies to the
45   # query list.
46   #
47   RPL_AWAY=301
48   # "<nick> :<away message>"
49   RPL_UNAWAY=305
50   # ":You are no longer marked as being away"
51   RPL_NOWAWAY=306
52   # ":You have been marked as being away"
53   #
54   # - These replies are used with the AWAY command (if
55   # allowed).  RPL_AWAY is sent to any client sending a
56   # PRIVMSG to a client which is away.  RPL_AWAY is only
57   # sent by the server to which the client is connected.
58   # Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
59   # client removes and sets an AWAY message.
60   #
61   RPL_WHOISUSER=311
62   # "<nick> <user> <host> * :<real name>"
63   RPL_WHOISSERVER=312
64   # "<nick> <server> :<server info>"
65   RPL_WHOISOPERATOR=313
66   # "<nick> :is an IRC operator"
67   RPL_WHOISIDLE=317
68   # "<nick> <integer> :seconds idle"
69   RPL_ENDOFWHOIS=318
70   # "<nick> :End of WHOIS list"
71   RPL_WHOISCHANNELS=319
72   # "<nick> :*( ( "@" / "+" ) <channel> " " )"
73   #
74   # - Replies 311 - 313, 317 - 319 are all replies
75   # generated in response to a WHOIS message.  Given that
76   # there are enough parameters present, the answering
77   # server MUST either formulate a reply out of the above
78   # numerics (if the query nick is found) or return an
79   # error reply.  The '*' in RPL_WHOISUSER is there as
80   # the literal character and not as a wild card.  For
81   # each reply set, only RPL_WHOISCHANNELS may appear
82   # more than once (for long lists of channel names).
83   # The '@' and '+' characters next to the channel name
84   # indicate whether a client is a channel operator or
85   # has been granted permission to speak on a moderated
86   # channel.  The RPL_ENDOFWHOIS reply is used to mark
87   # the end of processing a WHOIS message.
88   #
89   RPL_WHOWASUSER=314
90   # "<nick> <user> <host> * :<real name>"
91   RPL_ENDOFWHOWAS=369
92   # "<nick> :End of WHOWAS"
93   #
94   # - When replying to a WHOWAS message, a server MUST use
95   # the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
96   # ERR_WASNOSUCHNICK for each nickname in the presented
97   # list.  At the end of all reply batches, there MUST
98   # be RPL_ENDOFWHOWAS (even if there was only one reply
99   # and it was an error).
100   #
101   RPL_LISTSTART=321
102   # Obsolete. Not used.
103   #
104   RPL_LIST=322
105   # "<channel> <# visible> :<topic>"
106   RPL_LISTEND=323
107   # ":End of LIST"
108   #
109   # - Replies RPL_LIST, RPL_LISTEND mark the actual replies
110   # with data and end of the server's response to a LIST
111   # command.  If there are no channels available to return,
112   # only the end reply MUST be sent.
113   #
114   RPL_UNIQOPIS=325
115   # "<channel> <nickname>"
116   #
117   RPL_CHANNELMODEIS=324
118   # "<channel> <mode> <mode params>"
119   #
120   RPL_NOTOPIC=331
121   # "<channel> :No topic is set"
122   RPL_TOPIC=332
123   # "<channel> :<topic>"
124   #
125   # - When sending a TOPIC message to determine the
126   # channel topic, one of two replies is sent.  If
127   # the topic is set, RPL_TOPIC is sent back else
128   # RPL_NOTOPIC.
129   #
130   RPL_TOPIC_INFO=333
131   # <channel> <set by> <unixtime>
132   RPL_INVITING=341
133   # "<channel> <nick>"
134   #
135   # - Returned by the server to indicate that the
136   # attempted INVITE message was successful and is
137   # being passed onto the end client.
138   #
139   RPL_SUMMONING=342
140   # "<user> :Summoning user to IRC"
141   #
142   # - Returned by a server answering a SUMMON message to
143   # indicate that it is summoning that user.
144   #
145   RPL_INVITELIST=346
146   # "<channel> <invitemask>"
147   RPL_ENDOFINVITELIST=347
148   # "<channel> :End of channel invite list"
149   #
150   # - When listing the 'invitations masks' for a given channel,
151   # a server is required to send the list back using the
152   # RPL_INVITELIST and RPL_ENDOFINVITELIST messages.  A
153   # separate RPL_INVITELIST is sent for each active mask.
154   # After the masks have been listed (or if none present) a
155   # RPL_ENDOFINVITELIST MUST be sent.
156   #
157   RPL_EXCEPTLIST=348
158   # "<channel> <exceptionmask>"
159   RPL_ENDOFEXCEPTLIST=349
160   # "<channel> :End of channel exception list"
161   #
162   # - When listing the 'exception masks' for a given channel,
163   # a server is required to send the list back using the
164   # RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages.  A
165   # separate RPL_EXCEPTLIST is sent for each active mask.
166   # After the masks have been listed (or if none present)
167   # a RPL_ENDOFEXCEPTLIST MUST be sent.
168   #
169   RPL_VERSION=351
170   # "<version>.<debuglevel> <server> :<comments>"
171   #
172   # - Reply by the server showing its version details.
173   # The <version> is the version of the software being
174   # used (including any patchlevel revisions) and the
175   # <debuglevel> is used to indicate if the server is
176   # running in "debug mode".
177   #
178   # The "comments" field may contain any comments about
179   # the version or further version details.
180   #
181   RPL_WHOREPLY=352
182   # "<channel> <user> <host> <server> <nick>
183   # ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
184   # :<hopcount> <real name>"
185   #
186   RPL_ENDOFWHO=315
187   # "<name> :End of WHO list"
188   #
189   # - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
190   # to answer a WHO message.  The RPL_WHOREPLY is only
191   # sent if there is an appropriate match to the WHO
192   # query.  If there is a list of parameters supplied
193   # with a WHO message, a RPL_ENDOFWHO MUST be sent
194   # after processing each list item with <name> being
195   # the item.
196   #
197   RPL_NAMREPLY=353
198   # "( "=" / "*" / "@" ) <channel>
199   # :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
200   # - "@" is used for secret channels, "*" for private
201   # channels, and "=" for others (public channels).
202   #
203   RPL_ENDOFNAMES=366
204   # "<channel> :End of NAMES list"
205   #
206   # - To reply to a NAMES message, a reply pair consisting
207   # of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
208   # server back to the client.  If there is no channel
209   # found as in the query, then only RPL_ENDOFNAMES is
210   # returned.  The exception to this is when a NAMES
211   # message is sent with no parameters and all visible
212   # channels and contents are sent back in a series of
213   # RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
214   # the end.
215   #
216   RPL_LINKS=364
217   # "<mask> <server> :<hopcount> <server info>"
218   RPL_ENDOFLINKS=365
219   # "<mask> :End of LINKS list"
220   #
221   # - In replying to the LINKS message, a server MUST send
222   # replies back using the RPL_LINKS numeric and mark the
223   # end of the list using an RPL_ENDOFLINKS reply.
224   #
225   RPL_BANLIST=367
226   # "<channel> <banmask>"
227   RPL_ENDOFBANLIST=368
228   # "<channel> :End of channel ban list"
229   #
230   # - When listing the active 'bans' for a given channel,
231   # a server is required to send the list back using the
232   # RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
233   # RPL_BANLIST is sent for each active banmask.  After the
234   # banmasks have been listed (or if none present) a
235   # RPL_ENDOFBANLIST MUST be sent.
236   #
237   RPL_INFO=371
238   # ":<string>"
239   RPL_ENDOFINFO=374
240   # ":End of INFO list"
241   #
242   # - A server responding to an INFO message is required to
243   # send all its 'info' in a series of RPL_INFO messages
244   # with a RPL_ENDOFINFO reply to indicate the end of the
245   # replies.
246   #
247   RPL_MOTDSTART=375
248   # ":- <server> Message of the day - "
249   RPL_MOTD=372
250   # ":- <text>"
251   RPL_ENDOFMOTD=376
252   # ":End of MOTD command"
253   #
254   # - When responding to the MOTD message and the MOTD file
255   # is found, the file is displayed line by line, with
256   # each line no longer than 80 characters, using
257   # RPL_MOTD format replies.  These MUST be surrounded
258   # by a RPL_MOTDSTART (before the RPL_MOTDs) and an
259   # RPL_ENDOFMOTD (after).
260   #
261   RPL_YOUREOPER=381
262   # ":You are now an IRC operator"
263   #
264   # - RPL_YOUREOPER is sent back to a client which has
265   # just successfully issued an OPER message and gained
266   # operator status.
267   #
268   RPL_REHASHING=382
269   # "<config file> :Rehashing"
270   #
271   # - If the REHASH option is used and an operator sends
272   # a REHASH message, an RPL_REHASHING is sent back to
273   # the operator.
274   #
275   RPL_YOURESERVICE=383
276   # "You are service <servicename>"
277   #
278   # - Sent by the server to a service upon successful
279   # registration.
280   #
281   RPL_TIME=391
282   # "<server> :<string showing server's local time>"
283   #
284   # - When replying to the TIME message, a server MUST send
285   # the reply using the RPL_TIME format above.  The string
286   # showing the time need only contain the correct day and
287   # time there.  There is no further requirement for the
288   # time string.
289   #
290   RPL_USERSSTART=392
291   # ":UserID   Terminal  Host"
292   RPL_USERS=393
293   # ":<username> <ttyline> <hostname>"
294   RPL_ENDOFUSERS=394
295   # ":End of users"
296   RPL_NOUSERS=395
297   # ":Nobody logged in"
298   #
299   # - If the USERS message is handled by a server, the
300   # replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
301   # RPL_NOUSERS are used.  RPL_USERSSTART MUST be sent
302   # first, following by either a sequence of RPL_USERS
303   # or a single RPL_NOUSER.  Following this is
304   # RPL_ENDOFUSERS.
305   #
306   RPL_TRACELINK=200
307   # "Link <version & debug level> <destination>
308   # <next server> V<protocol version>
309   # <link uptime in seconds> <backstream sendq>
310   # <upstream sendq>"
311   RPL_TRACECONNECTING=201
312   # "Try. <class> <server>"
313   RPL_TRACEHANDSHAKE=202
314   # "H.S. <class> <server>"
315   RPL_TRACEUNKNOWN=203
316   # "???? <class> [<client IP address in dot form>]"
317   RPL_TRACEOPERATOR=204
318   # "Oper <class> <nick>"
319   RPL_TRACEUSER=205
320   # "User <class> <nick>"
321   RPL_TRACESERVER=206
322   # "Serv <class> <int>S <int>C <server>
323   # <nick!user|*!*>@<host|server> V<protocol version>"
324   RPL_TRACESERVICE=207
325   # "Service <class> <name> <type> <active type>"
326   RPL_TRACENEWTYPE=208
327   # "<newtype> 0 <client name>"
328   RPL_TRACECLASS=209
329   # "Class <class> <count>"
330   RPL_TRACERECONNECT=210
331   # Unused.
332   RPL_TRACELOG=261
333   # "File <logfile> <debug level>"
334   RPL_TRACEEND=262
335   # "<server name> <version & debug level> :End of TRACE"
336   #
337   # - The RPL_TRACE* are all returned by the server in
338   # response to the TRACE message.  How many are
339   # returned is dependent on the TRACE message and
340   # whether it was sent by an operator or not.  There
341   # is no predefined order for which occurs first.
342   # Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
343   # RPL_TRACEHANDSHAKE are all used for connections
344   # which have not been fully established and are either
345   # unknown, still attempting to connect or in the
346   # process of completing the 'server handshake'.
347   # RPL_TRACELINK is sent by any server which handles
348   # a TRACE message and has to pass it on to another
349   # server.  The list of RPL_TRACELINKs sent in
350   # response to a TRACE command traversing the IRC
351   # network should reflect the actual connectivity of
352   # the servers themselves along that path.
353   #
354   # RPL_TRACENEWTYPE is to be used for any connection
355   # which does not fit in the other categories but is
356   # being displayed anyway.
357   # RPL_TRACEEND is sent to indicate the end of the list.
358   #
359   RPL_LOCALUSERS=265
360   # ":Current local  users: 3  Max: 4"
361   RPL_GLOBALUSERS=266
362   # ":Current global users: 3  Max: 4"
363   RPL_STATSCONN=250
364   # "::Highest connection count: 4 (4 clients) (251 since server was
365   # (re)started)"
366   RPL_STATSLINKINFO=211
367   # "<linkname> <sendq> <sent messages>
368   # <sent Kbytes> <received messages>
369   # <received Kbytes> <time open>"
370   #
371   # - reports statistics on a connection.  <linkname>
372   # identifies the particular connection, <sendq> is
373   # the amount of data that is queued and waiting to be
374   # sent <sent messages> the number of messages sent,
375   # and <sent Kbytes> the amount of data sent, in
376   # Kbytes. <received messages> and <received Kbytes>
377   # are the equivalent of <sent messages> and <sent
378   # Kbytes> for received data, respectively.  <time
379   # open> indicates how long ago the connection was
380   # opened, in seconds.
381   #
382   RPL_STATSCOMMANDS=212
383   # "<command> <count> <byte count> <remote count>"
384   #
385   # - reports statistics on commands usage.
386   #
387   RPL_ENDOFSTATS=219
388   # "<stats letter> :End of STATS report"
389   #
390   RPL_STATSUPTIME=242
391   # ":Server Up %d days %d:%02d:%02d"
392   #
393   # - reports the server uptime.
394   #
395   RPL_STATSOLINE=243
396   # "O <hostmask> * <name>"
397   #
398   # - reports the allowed hosts from where user may become IRC
399   # operators.
400   #
401   RPL_UMODEIS=221
402   # "<user mode string>"
403   #
404   # - To answer a query about a client's own mode,
405   # RPL_UMODEIS is sent back.
406   #
407   RPL_SERVLIST=234
408   # "<name> <server> <mask> <type> <hopcount> <info>"
409   #
410   RPL_SERVLISTEND=235
411   # "<mask> <type> :End of service listing"
412   #
413   # - When listing services in reply to a SERVLIST message,
414   # a server is required to send the list back using the
415   # RPL_SERVLIST and RPL_SERVLISTEND messages.  A separate
416   # RPL_SERVLIST is sent for each service.  After the
417   # services have been listed (or if none present) a
418   # RPL_SERVLISTEND MUST be sent.
419   #
420   RPL_LUSERCLIENT=251
421   # ":There are <integer> users and <integer>
422   # services on <integer> servers"
423   RPL_LUSEROP=252
424   # "<integer> :operator(s) online"
425   RPL_LUSERUNKNOWN=253
426   # "<integer> :unknown connection(s)"
427   RPL_LUSERCHANNELS=254
428   # "<integer> :channels formed"
429   RPL_LUSERME=255
430   # ":I have <integer> clients and <integer>
431   # servers"
432   #
433   # - In processing an LUSERS message, the server
434   # sends a set of replies from RPL_LUSERCLIENT,
435   # RPL_LUSEROP, RPL_USERUNKNOWN,
436   # RPL_LUSERCHANNELS and RPL_LUSERME.  When
437   # replying, a server MUST send back
438   # RPL_LUSERCLIENT and RPL_LUSERME.  The other
439   # replies are only sent back if a non-zero count
440   # is found for them.
441   #
442   RPL_ADMINME=256
443   # "<server> :Administrative info"
444   RPL_ADMINLOC1=257
445   # ":<admin info>"
446   RPL_ADMINLOC2=258
447   # ":<admin info>"
448   RPL_ADMINEMAIL=259
449   # ":<admin info>"
450   #
451   # - When replying to an ADMIN message, a server
452   # is expected to use replies RPL_ADMINME
453   # through to RPL_ADMINEMAIL and provide a text
454   # message with each.  For RPL_ADMINLOC1 a
455   # description of what city, state and country
456   # the server is in is expected, followed by
457   # details of the institution (RPL_ADMINLOC2)
458   # and finally the administrative contact for the
459   # server (an email address here is REQUIRED)
460   # in RPL_ADMINEMAIL.
461   #
462   RPL_TRYAGAIN=263
463   # "<command> :Please wait a while and try again."
464   #
465   # - When a server drops a command without processing it,
466   # it MUST use the reply RPL_TRYAGAIN to inform the
467   # originating client.
468   #
469   # 5.2 Error Replies
470   #
471   # Error replies are found in the range from 400 to 599.
472   #
473   ERR_NOSUCHNICK=401
474   # "<nickname> :No such nick/channel"
475   #
476   # - Used to indicate the nickname parameter supplied to a
477   # command is currently unused.
478   #
479   ERR_NOSUCHSERVER=402
480   # "<server name> :No such server"
481   #
482   # - Used to indicate the server name given currently
483   # does not exist.
484   #
485   ERR_NOSUCHCHANNEL=403
486   # "<channel name> :No such channel"
487   #
488   # - Used to indicate the given channel name is invalid.
489   #
490   ERR_CANNOTSENDTOCHAN=404
491   # "<channel name> :Cannot send to channel"
492   #
493   # - Sent to a user who is either (a) not on a channel
494   # which is mode +n or (b) not a chanop (or mode +v) on
495   # a channel which has mode +m set or where the user is
496   # banned and is trying to send a PRIVMSG message to
497   # that channel.
498   #
499   ERR_TOOMANYCHANNELS=405
500   # "<channel name> :You have joined too many channels"
501   #
502   # - Sent to a user when they have joined the maximum
503   # number of allowed channels and they try to join
504   # another channel.
505   #
506   ERR_WASNOSUCHNICK=406
507   # "<nickname> :There was no such nickname"
508   #
509   # - Returned by WHOWAS to indicate there is no history
510   # information for that nickname.
511   #
512   ERR_TOOMANYTARGETS=407
513   # "<target> :<error code> recipients. <abort message>"
514   #
515   # - Returned to a client which is attempting to send a
516   # PRIVMSG/NOTICE using the user@host destination format
517   # and for a user@host which has several occurrences.
518   #
519   # - Returned to a client which trying to send a
520   # PRIVMSG/NOTICE to too many recipients.
521   #
522   # - Returned to a client which is attempting to JOIN a safe
523   # channel using the shortname when there are more than one
524   # such channel.
525   #
526   ERR_NOSUCHSERVICE=408
527   # "<service name> :No such service"
528   #
529   # - Returned to a client which is attempting to send a SQUERY
530   # to a service which does not exist.
531   #
532   ERR_NOORIGIN=409
533   # ":No origin specified"
534   #
535   # - PING or PONG message missing the originator parameter.
536   #
537   ERR_NORECIPIENT=411
538   # ":No recipient given (<command>)"
539   ERR_NOTEXTTOSEND=412
540   # ":No text to send"
541   ERR_NOTOPLEVEL=413
542   # "<mask> :No toplevel domain specified"
543   ERR_WILDTOPLEVEL=414
544   # "<mask> :Wildcard in toplevel domain"
545   ERR_BADMASK=415
546   # "<mask> :Bad Server/host mask"
547   #
548   # - 412 - 415 are returned by PRIVMSG to indicate that
549   # the message wasn't delivered for some reason.
550   # ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
551   # are returned when an invalid use of
552   # "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
553   #
554   ERR_UNKNOWNCOMMAND=421
555   # "<command> :Unknown command"
556   #
557   # - Returned to a registered client to indicate that the
558   # command sent is unknown by the server.
559   #
560   ERR_NOMOTD=422
561   # ":MOTD File is missing"
562   #
563   # - Server's MOTD file could not be opened by the server.
564   #
565   ERR_NOADMININFO=423
566   # "<server> :No administrative info available"
567   #
568   # - Returned by a server in response to an ADMIN message
569   # when there is an error in finding the appropriate
570   # information.
571   #
572   ERR_FILEERROR=424
573   # ":File error doing <file op> on <file>"
574   #
575   # - Generic error message used to report a failed file
576   # operation during the processing of a message.
577   #
578   ERR_NONICKNAMEGIVEN=431
579   # ":No nickname given"
580   #
581   # - Returned when a nickname parameter expected for a
582   # command and isn't found.
583   #
584   ERR_ERRONEUSNICKNAME=432
585   # "<nick> :Erroneous nickname"
586   #
587   # - Returned after receiving a NICK message which contains
588   # characters which do not fall in the defined set.  See
589   # section 2.3.1 for details on valid nicknames.
590   #
591   ERR_NICKNAMEINUSE=433
592   # "<nick> :Nickname is already in use"
593   #
594   # - Returned when a NICK message is processed that results
595   # in an attempt to change to a currently existing
596   # nickname.
597   #
598   ERR_NICKCOLLISION=436
599   # "<nick> :Nickname collision KILL from <user>@<host>"
600   #
601   # - Returned by a server to a client when it detects a
602   # nickname collision (registered of a NICK that
603   # already exists by another server).
604   #
605   ERR_UNAVAILRESOURCE=437
606   # "<nick/channel> :Nick/channel is temporarily unavailable"
607   #
608   # - Returned by a server to a user trying to join a channel
609   # currently blocked by the channel delay mechanism.
610   #
611   # - Returned by a server to a user trying to change nickname
612   # when the desired nickname is blocked by the nick delay
613   # mechanism.
614   #
615   ERR_USERNOTINCHANNEL=441
616   # "<nick> <channel> :They aren't on that channel"
617   #
618   # - Returned by the server to indicate that the target
619   # user of the command is not on the given channel.
620   #
621   ERR_NOTONCHANNEL=442
622   # "<channel> :You're not on that channel"
623   #
624   # - Returned by the server whenever a client tries to
625   # perform a channel affecting command for which the
626   # client isn't a member.
627   #
628   ERR_USERONCHANNEL=443
629   # "<user> <channel> :is already on channel"
630   #
631   # - Returned when a client tries to invite a user to a
632   # channel they are already on.
633   #
634   ERR_NOLOGIN=444
635   # "<user> :User not logged in"
636   #
637   # - Returned by the summon after a SUMMON command for a
638   # user was unable to be performed since they were not
639   # logged in.
640   #
641   #
642   ERR_SUMMONDISABLED=445
643   # ":SUMMON has been disabled"
644   #
645   # - Returned as a response to the SUMMON command.  MUST be
646   # returned by any server which doesn't implement it.
647   #
648   ERR_USERSDISABLED=446
649   # ":USERS has been disabled"
650   #
651   # - Returned as a response to the USERS command.  MUST be
652   # returned by any server which does not implement it.
653   #
654   ERR_NOTREGISTERED=451
655   # ":You have not registered"
656   #
657   # - Returned by the server to indicate that the client
658   # MUST be registered before the server will allow it
659   # to be parsed in detail.
660   #
661   ERR_NEEDMOREPARAMS=461
662   # "<command> :Not enough parameters"
663   #
664   # - Returned by the server by numerous commands to
665   # indicate to the client that it didn't supply enough
666   # parameters.
667   #
668   ERR_ALREADYREGISTRED=462
669   # ":Unauthorized command (already registered)"
670   #
671   # - Returned by the server to any link which tries to
672   # change part of the registered details (such as
673   # password or user details from second USER message).
674   #
675   ERR_NOPERMFORHOST=463
676   # ":Your host isn't among the privileged"
677   #
678   # - Returned to a client which attempts to register with
679   # a server which does not been setup to allow
680   # connections from the host the attempted connection
681   # is tried.
682   #
683   ERR_PASSWDMISMATCH=464
684   # ":Password incorrect"
685   #
686   # - Returned to indicate a failed attempt at registering
687   # a connection for which a password was required and
688   # was either not given or incorrect.
689   #
690   ERR_YOUREBANNEDCREEP=465
691   # ":You are banned from this server"
692   #
693   # - Returned after an attempt to connect and register
694   # yourself with a server which has been setup to
695   # explicitly deny connections to you.
696   #
697   ERR_YOUWILLBEBANNED=466
698   #
699   # - Sent by a server to a user to inform that access to the
700   # server will soon be denied.
701   #
702   ERR_KEYSET=467
703   # "<channel> :Channel key already set"
704   ERR_CHANNELISFULL=471
705   # "<channel> :Cannot join channel (+l)"
706   ERR_UNKNOWNMODE=472
707   # "<char> :is unknown mode char to me for <channel>"
708   ERR_INVITEONLYCHAN=473
709   # "<channel> :Cannot join channel (+i)"
710   ERR_BANNEDFROMCHAN=474
711   # "<channel> :Cannot join channel (+b)"
712   ERR_BADCHANNELKEY=475
713   # "<channel> :Cannot join channel (+k)"
714   ERR_BADCHANMASK=476
715   # "<channel> :Bad Channel Mask"
716   ERR_NOCHANMODES=477
717   # "<channel> :Channel doesn't support modes"
718   ERR_BANLISTFULL=478
719   # "<channel> <char> :Channel list is full"
720   #
721   ERR_NOPRIVILEGES=481
722   # ":Permission Denied- You're not an IRC operator"
723   #
724   # - Any command requiring operator privileges to operate
725   # MUST return this error to indicate the attempt was
726   # unsuccessful.
727   #
728   ERR_CHANOPRIVSNEEDED=482
729   # "<channel> :You're not channel operator"
730   #
731   # - Any command requiring 'chanop' privileges (such as
732   # MODE messages) MUST return this error if the client
733   # making the attempt is not a chanop on the specified
734   # channel.
735   #
736   #
737   ERR_CANTKILLSERVER=483
738   # ":You can't kill a server!"
739   #
740   # - Any attempts to use the KILL command on a server
741   # are to be refused and this error returned directly
742   # to the client.
743   #
744   ERR_RESTRICTED=484
745   # ":Your connection is restricted!"
746   #
747   # - Sent by the server to a user upon connection to indicate
748   # the restricted nature of the connection (user mode "+r").
749   #
750   ERR_UNIQOPPRIVSNEEDED=485
751   # ":You're not the original channel operator"
752   #
753   # - Any MODE requiring "channel creator" privileges MUST
754   # return this error if the client making the attempt is not
755   # a chanop on the specified channel.
756   #
757   ERR_NOOPERHOST=491
758   # ":No O-lines for your host"
759   #
760   # - If a client sends an OPER message and the server has
761   # not been configured to allow connections from the
762   # client's host as an operator, this error MUST be
763   # returned.
764   #
765   ERR_UMODEUNKNOWNFLAG=501
766   # ":Unknown MODE flag"
767   #
768   # - Returned by the server to indicate that a MODE
769   # message was sent with a nickname parameter and that
770   # the a mode flag sent was not recognized.
771   #
772   ERR_USERSDONTMATCH=502
773   # ":Cannot change mode for other users"
774   #
775   # - Error sent to any user trying to view or change the
776   # user mode for a user other than themselves.
777   #
778   # 5.3 Reserved numerics
779   #
780   # These numerics are not described above since they fall into one of
781   # the following categories:
782   #
783   # 1. no longer in use;
784   #
785   # 2. reserved for future planned use;
786   #
787   # 3. in current use but are part of a non-generic 'feature' of
788   # the current IRC server.
789   RPL_SERVICEINFO=231
790   RPL_ENDOFSERVICES=232
791   RPL_SERVICE=233
792   RPL_NONE=300
793   RPL_WHOISCHANOP=316
794   RPL_KILLDONE=361
795   RPL_CLOSING=362
796   RPL_CLOSEEND=363
797   RPL_INFOSTART=373
798   RPL_MYPORTIS=384
799   RPL_STATSCLINE=213
800   RPL_STATSNLINE=214
801   RPL_STATSILINE=215
802   RPL_STATSKLINE=216
803   RPL_STATSQLINE=217
804   RPL_STATSYLINE=218
805   RPL_STATSVLINE=240
806   RPL_STATSLLINE=241
807   RPL_STATSHLINE=244
808   RPL_STATSSLINE=244
809   RPL_STATSPING=246
810   RPL_STATSBLINE=247
811   ERR_NOSERVICEHOST=492
812   RPL_DATASTR=290
813
814   # implements RFC 2812 and prior IRC RFCs.
815   # clients register handler proc{}s for different server events and IrcClient
816   # handles dispatch
817   class IrcClient
818
819     attr_reader :server, :client
820
821     # create a new IrcClient instance
822     def initialize
823       @server = Server.new         # The Server
824       @client = @server.user("")   # The User representing the client on this Server
825
826       @handlers = Hash.new
827
828       # This is used by some messages to build lists of users that
829       # will be delegated when the ENDOF... message is received
830       @tmpusers = []
831     end
832
833     # key::   server event to handle
834     # value:: proc object called when event occurs
835     # set a handler for a server event
836     #
837     # ==server events currently supported:
838     #
839     # TODO handle errors ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL, ERR_CANNOTSENDTOCHAN
840     #
841     # welcome::     server welcome message on connect
842     # yourhost::    your host details (on connection)
843     # created::     when the server was started
844     # isupport::    information about what this server supports
845     # ping::        server pings you (default handler returns a pong)
846     # nicktaken::   you tried to change nick to one that's in use
847     # badnick::     you tried to change nick to one that's invalid
848     # topic::       someone changed the topic of a channel
849     # topicinfo::   on joining a channel or asking for the topic, tells you
850     #               who set it and when
851     # names::       server sends list of channel members when you join
852     # motd::        server message of the day
853     # privmsg::     privmsg, the core of IRC, a message to you from someone
854     # public::      optionally instead of getting privmsg you can hook to only
855     #               the public ones...
856     # msg::         or only the private ones, or both
857     # kick::        someone got kicked from a channel
858     # part::        someone left a channel
859     # quit::        someone quit IRC
860     # join::        someone joined a channel
861     # changetopic:: the topic of a channel changed
862     # invite::      you are invited to a channel
863     # nick::        someone changed their nick
864     # mode::        a mode change
865     # notice::      someone sends you a notice
866     # unknown::     any other message not handled by the above
867     def []=(key, value)
868       @handlers[key] = value
869     end
870
871     # key:: event name
872     # remove a handler for a server event
873     def deletehandler(key)
874       @handlers.delete(key)
875     end
876
877     # takes a server string, checks for PING, PRIVMSG, NOTIFY, etc, and parses
878     # numeric server replies, calling the appropriate handler for each, and
879     # sending it a hash containing the data from the server
880     def process(serverstring)
881       data = Hash.new
882       data[:serverstring] = serverstring
883
884       unless serverstring =~ /^(:(\S+)\s)?(\S+)(\s(.*))?/
885         raise "Unparseable Server Message!!!: #{serverstring}"
886       end
887
888       prefix, command, params = $2, $3, $5
889
890       if prefix != nil
891         # Most servers will send a full nick!user@host prefix for
892         # messages from users. Therefore, when the prefix doesn't match this
893         # syntax it's usually the server hostname.
894         #
895         # This is not always true, though, since some servers do not send a
896         # full hostmask for user messages.
897         #
898         if prefix =~ /^(?:\S+)(?:!\S+)?@(?:\S+)$/
899           data[:source] = @server.user(prefix)
900         else
901           if @server.hostname
902             if @server.hostname != prefix
903               debug "Origin #{prefix} for message\n\t#{serverstring.inspect}\nis neither a user hostmask nor the server hostname, assuming it's a nick"
904               data[:source] = @server.user(prefix)
905             else
906               data[:source] = @server
907             end
908           else
909             @server.instance_variable_set(:@hostname, data[:source])
910             data[:source] = @server
911           end
912         end
913       end
914
915       # split parameters in an array
916       argv = []
917       params.scan(/(?!:)(\S+)|:(.*)/) { argv << ($1 || $2) } if params
918
919       if command =~ /^(\d+)$/ # Numeric replies
920         data[:target] = argv[0]
921         # A numeric reply /should/ be directed at the client, except when we're connecting with a used nick, in which case
922         # it's directed at '*'
923         not_us = !([@client.nick, '*'].include?(data[:target]))
924         if not_us
925           warning "Server reply #{serverstring.inspect} directed at #{data[:target]} instead of client (#{@client.nick})"
926         end
927
928         num=command.to_i
929         case num
930         when RPL_WELCOME
931           # "Welcome to the Internet Relay Network
932           # <nick>!<user>@<host>"
933           if not_us
934             warning "Server thinks client (#{@client.inspect}) has a different nick"
935             @client.nick = data[:target]
936           end
937           if argv[1] =~ /(\S+)(?:!(\S+?))?@(\S+)/
938             nick = $1
939             user = $2
940             host = $2
941             warning "Welcome message nick mismatch (#{nick} vs #{data[:target]})" if nick != data[:target]
942             @client.user = user if user
943             @client.host = host if host
944           end
945           handle(:welcome, data)
946         when RPL_YOURHOST
947           # "Your host is <servername>, running version <ver>"
948           data[:message] = argv[1]
949           handle(:yourhost, data)
950         when RPL_CREATED
951           # "This server was created <date>"
952           data[:message] = argv[1]
953           handle(:created, data)
954         when RPL_MYINFO
955           # "<servername> <version> <available user modes>
956           # <available channel modes>"
957           @server.parse_my_info(params.split(' ', 2).last)
958           data[:servername] = @server.hostname
959           data[:version] = @server.version
960           data[:usermodes] = @server.usermodes
961           data[:chanmodes] = @server.chanmodes
962           handle(:myinfo, data)
963         when RPL_ISUPPORT
964           # "PREFIX=(ov)@+ CHANTYPES=#& :are supported by this server"
965           # "MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63
966           # TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=#
967           # PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer :are available
968           # on this server"
969           #
970           @server.parse_isupport(argv[1..-2].join(' '))
971           handle(:isupport, data)
972         when ERR_NICKNAMEINUSE
973           # "* <nick> :Nickname is already in use"
974           data[:nick] = argv[1]
975           data[:message] = argv[2]
976           handle(:nicktaken, data)
977         when ERR_ERRONEUSNICKNAME
978           # "* <nick> :Erroneous nickname"
979           data[:nick] = argv[1]
980           data[:message] = argv[2]
981           handle(:badnick, data)
982         when RPL_TOPIC
983           data[:channel] = @server.get_channel(argv[1])
984           data[:topic] = argv[2]
985
986           if data[:channel]
987             data[:channel].topic.text = data[:topic]
988           else
989             warning "Received topic #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
990           end
991
992           handle(:topic, data)
993         when RPL_TOPIC_INFO
994           data[:nick] = @server.user(argv[0])
995           data[:channel] = @server.get_channel(argv[1])
996           data[:source] = @server.user(argv[2])
997           data[:time] = Time.at(argv[3].to_i)
998
999           if data[:channel]
1000             data[:channel].topic.set_by = data[:nick]
1001             data[:channel].topic.set_on = data[:time]
1002           else
1003             warning "Received topic #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
1004           end
1005
1006           handle(:topicinfo, data)
1007         when RPL_NAMREPLY
1008           # "( "=" / "*" / "@" ) <channel>
1009           # :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
1010           # - "@" is used for secret channels, "*" for private
1011           # channels, and "=" for others (public channels).
1012           data[:channeltype] = argv[1]
1013           data[:channel] = argv[2]
1014
1015           chan = @server.get_channel(data[:channel])
1016           unless chan
1017             warning "Received names #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
1018             return
1019           end
1020
1021           users = []
1022           argv[3].scan(/\S+/).each { |u|
1023             # FIXME beware of servers that allow multiple prefixes
1024             if(u =~ /^([#{@server.supports[:prefix][:prefixes].join}])?(.*)$/)
1025               umode = $1
1026               user = $2
1027               users << [user, umode]
1028             end
1029           }
1030
1031           users.each { |ar|
1032             u = @server.user(ar[0])
1033             chan.add_user(u, :silent => true)
1034             debug "Adding user #{u}"
1035             if ar[1]
1036               m = @server.supports[:prefix][:prefixes].index(ar[1].to_sym)
1037               ms = @server.supports[:prefix][:modes][m]
1038               debug "\twith mode #{ar[1]} (#{ms})"
1039               chan.mode[ms].set(u)
1040             end
1041           }
1042           @tmpusers += users
1043         when RPL_ENDOFNAMES
1044           data[:channel] = argv[1]
1045           data[:users] = @tmpusers
1046           handle(:names, data)
1047           @tmpusers = Array.new
1048         when RPL_LUSERCLIENT
1049           # ":There are <integer> users and <integer>
1050           # services on <integer> servers"
1051           data[:message] = argv[1]
1052           handle(:luserclient, data)
1053         when RPL_LUSEROP
1054           # "<integer> :operator(s) online"
1055           data[:ops] = argv[1].to_i
1056           handle(:luserop, data)
1057         when RPL_LUSERUNKNOWN
1058           # "<integer> :unknown connection(s)"
1059           data[:unknown] = argv[1].to_i
1060           handle(:luserunknown, data)
1061         when RPL_LUSERCHANNELS
1062           # "<integer> :channels formed"
1063           data[:channels] = argv[1].to_i
1064           handle(:luserchannels, data)
1065         when RPL_LUSERME
1066           # ":I have <integer> clients and <integer> servers"
1067           data[:message] = argv[1]
1068           handle(:luserme, data)
1069         when ERR_NOMOTD
1070           # ":MOTD File is missing"
1071           data[:message] = argv[1]
1072           handle(:motd_missing, data)
1073         when RPL_LOCALUSERS
1074           # ":Current local  users: 3  Max: 4"
1075           data[:message] = argv[1]
1076           handle(:localusers, data)
1077         when RPL_GLOBALUSERS
1078           # ":Current global users: 3  Max: 4"
1079           data[:message] = argv[1]
1080           handle(:globalusers, data)
1081         when RPL_STATSCONN
1082           # ":Highest connection count: 4 (4 clients) (251 since server was
1083           # (re)started)"
1084           data[:message] = argv[1]
1085           handle(:statsconn, data)
1086         when RPL_MOTDSTART
1087           # "<nick> :- <server> Message of the Day -"
1088           if argv[1] =~ /^-\s+(\S+)\s/
1089             server = $1
1090             @motd = ""
1091           end
1092         when RPL_MOTD
1093           if(argv[1] =~ /^-\s+(.*)$/)
1094             @motd << $1
1095             @motd << "\n"
1096           end
1097         when RPL_ENDOFMOTD
1098           data[:motd] = @motd
1099           handle(:motd, data)
1100         when RPL_DATASTR
1101           data[:text] = argv[1]
1102           handle(:datastr, data)
1103         else
1104           handle(:unknown, data)
1105         end
1106         return # We've processed the numeric reply
1107       end
1108
1109       # Otherwise, the command should be a single word
1110       case command.to_sym
1111       when :PING
1112         data[:pingid] = argv[0]
1113         handle(:ping, data)
1114       when :PONG
1115         data[:pingid] = argv[0]
1116         handle(:pong, data)
1117       when :PRIVMSG
1118         # you can either bind to 'PRIVMSG', to get every one and
1119         # parse it yourself, or you can bind to 'MSG', 'PUBLIC',
1120         # etc and get it all nicely split up for you.
1121
1122         begin
1123           data[:target] = @server.user_or_channel(argv[0])
1124         rescue
1125           # The previous may fail e.g. when the target is a server or something
1126           # like that (e.g. $<mask>). In any of these cases, we just use the
1127           # String as a target
1128           # FIXME we probably want to explicitly check for the #<mask> $<mask>
1129           data[:target] = argv[0]
1130         end
1131         data[:message] = argv[1]
1132         handle(:privmsg, data)
1133
1134         # Now we split it
1135         if data[:target].kind_of?(Channel)
1136           handle(:public, data)
1137         else
1138           handle(:msg, data)
1139         end
1140       when :NOTICE
1141         begin
1142           data[:target] = @server.user_or_channel(argv[0])
1143         rescue
1144           # The previous may fail e.g. when the target is a server or something
1145           # like that (e.g. $<mask>). In any of these cases, we just use the
1146           # String as a target
1147           # FIXME we probably want to explicitly check for the #<mask> $<mask>
1148           data[:target] = argv[0]
1149         end
1150         data[:message] = argv[1]
1151         case data[:source]
1152         when User
1153           handle(:notice, data)
1154         else
1155           # "server notice" (not from user, noone to reply to)
1156           handle(:snotice, data)
1157         end
1158       when :KICK
1159         data[:channel] = @server.channel(argv[0])
1160         data[:target] = @server.user(argv[1])
1161         data[:message] = argv[2]
1162
1163         @server.delete_user_from_channel(data[:target], data[:channel])
1164         if data[:target] == @client
1165           @server.delete_channel(data[:channel])
1166         end
1167
1168         handle(:kick, data)
1169       when :PART
1170         data[:channel] = @server.channel(argv[0])
1171         data[:message] = argv[1]
1172
1173         @server.delete_user_from_channel(data[:source], data[:channel])
1174         if data[:source] == @client
1175           @server.delete_channel(data[:channel])
1176         end
1177
1178         handle(:part, data)
1179       when :QUIT
1180         data[:message] = argv[0]
1181         data[:was_on] = @server.channels.inject(ChannelList.new) { |list, ch|
1182           list << ch if ch.has_user?(data[:source])
1183           list
1184         }
1185
1186         @server.delete_user(data[:source])
1187
1188         handle(:quit, data)
1189       when :JOIN
1190         data[:channel] = @server.channel(argv[0])
1191         data[:channel].add_user(data[:source])
1192
1193         handle(:join, data)
1194       when :TOPIC
1195         data[:channel] = @server.channel(argv[0])
1196         data[:topic] = Channel::Topic.new(argv[1], data[:source], Time.new)
1197         data[:channel].topic.replace(data[:topic])
1198
1199         handle(:changetopic, data)
1200       when :INVITE
1201         data[:target] = @server.user(argv[0])
1202         data[:channel] = @server.channel(argv[1])
1203
1204         handle(:invite, data)
1205       when :NICK
1206         data[:is_on] = @server.channels.inject(ChannelList.new) { |list, ch|
1207           list << ch if ch.has_user?(data[:source])
1208           list
1209         }
1210
1211         data[:newnick] = argv[0]
1212         data[:oldnick] = data[:source].nick.dup
1213         data[:source].nick = data[:newnick]
1214
1215         debug "#{data[:oldnick]} (now #{data[:newnick]}) was on #{data[:is_on].join(', ')}"
1216
1217         handle(:nick, data)
1218       when :MODE
1219         # MODE ([+-]<modes> (<params>)*)*
1220         # When a MODE message is received by a server,
1221         # Type C will have parameters too, so we must
1222         # be able to consume parameters for all
1223         # but Type D modes
1224
1225         data[:channel] = @server.user_or_channel(argv[0])
1226         data[:modestring] = argv[1..-1].join(" ")
1227         case data[:channel]
1228         when User
1229           # TODO
1230           warning "Unhandled user mode message '#{serverstring}'"
1231         else
1232           # data[:modes] is an array where each element
1233           # is either a flag which doesn't need parameters
1234           # or an array with a flag which needs parameters
1235           # and the corresponding parameter
1236           data[:modes] = []
1237           # array of indices in data[:modes] where parameters
1238           # are needed
1239           who_wants_params = []
1240
1241           argv[1..-1].each { |arg|
1242             setting = arg[0].chr
1243             if "+-".include?(setting)
1244               arg[1..-1].each_byte { |b|
1245                 m = b.chr
1246                 case m.to_sym
1247                 when *@server.supports[:chanmodes][:typea]
1248                   data[:modes] << [setting + m]
1249                   who_wants_params << data[:modes].length - 1
1250                 when *@server.supports[:chanmodes][:typeb]
1251                   data[:modes] << [setting + m]
1252                   who_wants_params << data[:modes].length - 1
1253                 when *@server.supports[:chanmodes][:typec]
1254                   if setting == "+"
1255                     data[:modes] << [setting + m]
1256                     who_wants_params << data[:modes].length - 1
1257                   else
1258                     data[:modes] << setting + m
1259                   end
1260                 when *@server.supports[:chanmodes][:typed]
1261                   data[:modes] << setting + m
1262                 when *@server.supports[:prefix][:modes]
1263                   data[:modes] << [setting + m]
1264                   who_wants_params << data[:modes].length - 1
1265                 else
1266                   warning "Unknown mode #{m} in #{serverstring.inspect}"
1267                 end
1268               }
1269             else
1270               idx = who_wants_params.shift
1271               if idx.nil?
1272                 warning "Oops, problems parsing #{serverstring.inspect}"
1273                 break
1274               end
1275               data[:modes][idx] << arg
1276             end
1277           }
1278         end
1279
1280         data[:modes].each { |mode|
1281           case mode
1282           when Array
1283             set = mode[0][0].chr == "+" ? :set : :reset
1284             key = mode[0][1].chr.to_sym
1285             val = mode[1]
1286             data[:channel].mode[key].send(set, val)
1287           else
1288             set = mode[0].chr == "+" ? :set : :reset
1289             key = mode[1].chr.to_sym
1290             data[:channel].mode[key].send(set)
1291           end
1292         } if data[:modes]
1293
1294         handle(:mode, data)
1295       else
1296         warning "Unknown message #{serverstring.inspect}"
1297         handle(:unknown, data)
1298       end
1299     end
1300
1301     private
1302
1303     # key::  server event name
1304     # data:: hash containing data about the event, passed to the proc
1305     # call client's proc for an event, if they set one as a handler
1306     def handle(key, data)
1307       if(@handlers.has_key?(key))
1308         @handlers[key].call(data)
1309       end
1310     end
1311   end
1312 end