1 /++
2     Definitions of struct aggregates used throughout the library, representing
3     [IRCEvent]s and thereto related objects like [IRCServer] and [IRCUser].
4 
5     Things related to actually parsing IRC do not belong here; what's here
6     should only be applicable to be used as a header.
7 
8     The only lu dependency should be [lu.uda].
9  +/
10 module dialect.defs;
11 
12 private:
13 
14 import lu.uda;
15 
16 public:
17 
18 final:
19 pure:
20 nothrow:
21 @nogc:
22 
23 
24 // IRCEvent
25 /++
26     A single IRC event, parsed from server input.
27 
28     The [IRCEvent] struct is a construct with fields extracted from raw server
29     strings. Since structs are not polymorphic the [IRCEvent.Type|Type] enum
30     dictates what kind of event it is.
31  +/
32 struct IRCEvent
33 {
34 private:
35     import std.typecons : Nullable;
36 
37     /++
38         How many elements should be allocated for auxiliary strings.
39 
40         `RPL_ISUPPORT` can contain a lot of strings and should be considered the
41         worst case.
42      +/
43     enum numAuxStrings = 16;
44 
45     /++
46         How many elements should be allocated for counts.
47      +/
48     enum numCounts = 16;
49 
50 public:
51     /++
52         [Type]s of [IRCEvent]s.
53 
54         Taken from https://tools.ietf.org/html/rfc1459 with many additions.
55 
56         Some are outright fabrications of ours, like [Type.CHAN|CHAN] and
57         [Type.QUERY|QUERY]. These are not prefixed with `RPL_` and `ERR_`
58         (but not all such are made up, like [Type.AWAY|AWAY] and
59         [Type.CHGHOST|CHGHOST] that are properly [Type.AWAY|AWAY] and
60         [Type.CHGHOST|CHGHOST]).
61 
62         See_Also:
63             https://tools.ietf.org/html/rfc1459
64             https://www.alien.net.au/irc/irc2numerics.html
65             https://defs.ircdocs.horse
66      +/
67     enum Type
68     {
69         UNSET,      /// Invalid [IRCEvent] with no [Type].
70         ANY,        /// Meta-[Type] for *any* kind of [IRCEvent].
71         ERROR,      /// Generic error [Type].
72         NUMERIC,    /// *Numeric* event of an unknown [Type].
73         PRIVMSG,    /// Private message or channel message.
74         CHAN,       /// Channel message.
75         QUERY,      /// Private query message.
76         EMOTE,      /// CTCP **ACTION**; `/me slaps Foo with a large trout`.
77         SELFQUERY,  /// A message from you in a query (CAP `znc.in/self-message`).
78         SELFCHAN,   /// A message from you in a channel (CAP `znc.in/self-message`).
79         SELFEMOTE,  /// A CTCP ACTION from you. (Twitch etc)
80         AWAY,       /// Someone flagged themselves as away (from keyboard).
81         BACK,       /// Someone returned from `AWAY`.
82         JOIN,       /// Someone joined a channel.
83         PART,       /// Someone left a channel.
84         QUIT,       /// Someone quit the server.
85         KICK,       /// Someone was kicked from a channel.
86         INVITE,     /// You were invited to a channel.
87         NOTICE,     /// A server `NOTICE` event.
88         PING,       /// The server periodically `PING`ed you.
89         PONG,       /// The server actually `PONG`ed you.
90         NICK,       /// Someone changed nickname.
91         MODE,       /// Someone changed the modes of a channel.
92         SELFQUIT,   /// You quit the server.
93         SELFJOIN,   /// You joined a channel.
94         SELFPART,   /// You left a channel.
95         SELFMODE,   /// You changed your modes.
96         SELFNICK,   /// You changed your nickname.
97         SELFKICK,   /// You were kicked.
98         TOPIC,      /// Someone changed channel topic.
99         CAP,        /// CAPability exchange during connect.
100         CTCP_VERSION,/// Something requested your version info.
101         CTCP_TIME,  /// Something requested your time.
102         CTCP_PING,  /// Something pinged you.
103         CTCP_CLIENTINFO,/// Something asked what CTCP events the client can handle.
104         CTCP_DCC,   /// Something requested a DCC connection (chat, file transfer).
105         CTCP_SOURCE,/// Something requested an URL to the client source code.
106         CTCP_USERINFO,/// Something requested the nickname and user of the client.
107         CTCP_FINGER,/// Someone requested miscellaneous info about the client.
108         CTCP_LAG,   /// Something requested LAG info?
109         CTCP_AVATAR,/// Someone requested an avatar image.
110         CTCP_SLOTS, /// Someone broadcast their file transfer slots.
111         ACCOUNT,    /// Someone logged in on nickname services.
112         WALLOPS,    /// "WALLOPS messages are for broadcasting network information and its status to following users."
113         SASL_AUTHENTICATE,/// SASL authentication negotiation.
114         AUTH_CHALLENGE,   /// Authentication challenge.
115         AUTH_FAILURE,     /// Authentication failure.
116         AUTH_SUCCESS,     /// Authentication success.
117         CHGHOST,          /// User "changes host", which is a thing on some networks.
118         CHANNELFORBIDDEN, // = 926,     // <nickname> <channel> :Channel <channel> is forbidden: This channel is closed by request of the channel operators.
119         BOTSNOTWELCOME,   // = 931,     // <nickname> :Malicious bot, spammers, and other automated systems of dubious origins are NOT welcome here.
120         ENDOFSPAMFILTERLIST,// = 940,   // <nickname> <channel> :End of channel spamfilter list
121         SPAMFILTERLIST,   // = 941,
122         NICKUNLOCKED,     // = 945,
123         NICKNOTLOCKED,    // = 946,
124         ENDOFEXEMPTOPSLIST,// = 953 // End of exempt channel ops list.
125         MODELIST,         // = 961 /// +noctcp +nickflood 5:60 +nonotice +flood 30:5 +joinflood 5:1 +noextmsg +topiclock +globalflood 10:5
126         ENDOFMODELIST,    // = 960 // End of mode list.
127         ENDOFCHANNELACCLIST, // = 911 // End of Channel Access List
128         THISSERVERINSTEAD,// = 010 // <nickname> <new server> +<port> :Please use this Server/Port instead$
129 
130         // Twitch specifics
131         USERSTATE,        /// Twitch user information.
132         ROOMSTATE,        /// Twitch channel information.
133         GLOBALUSERSTATE,  /// Twitch information about self upon login.
134         CLEARCHAT,        /// Twitch `CLEARCHAT` event, clearing the chat or banning a user.
135         CLEARMSG,         /// Twitch `CLEARMSG` event, deletes a sent message.
136         USERNOTICE,       /// Twitch subscription or resubscription event.
137         RECONNECT,        /// Twitch `RECONNECT` event; Twitch IRC processes restarting.
138         WHISPER,          /// Twitch private query message.
139         TWITCH_NOTICE,    /// Twitch generic server notice, see `event.aux`.
140         TWITCH_ERROR,     /// Twitch generic error, see `event.aux`.
141         TWITCH_TIMEOUT,   /// Twitch temporary ban (seconds in `count`).
142         TWITCH_BAN,       /// Twitch permanent ban.
143         TWITCH_SUB,       /// Twitch subscription event, including resubs.
144         TWITCH_CHEER,     /// Twitch "bits" donation.
145         TWITCH_SUBGIFT,   /// Twitch subscription gift event.
146         TWITCH_BITSBADGETIER, /// Twitch event, unsure of its meaning.
147         TWITCH_RAID,      /// Twitch raid.
148         TWITCH_UNRAID,    /// End of a Twitch raid.
149         TWITCH_RITUAL,    /// Twitch Ritual event.
150         TWITCH_REWARDGIFT,/// Twitch "reward gift".
151         TWITCH_GIFTCHAIN, /// Twitch "continuing the gift sub"
152         TWITCH_SUBUPGRADE,/// Twitch, someone paying to upgrade their subscription.
153         TWITCH_CHARITY,   /// Twitch charity donation.
154         TWITCH_BULKGIFT,  /// Twitch no-target multiple gift event.
155         TWITCH_EXTENDSUB, /// Twitch sub extension.
156         TWITCH_GIFTRECEIVED , /// Twitch Prime community gift received.
157         TWITCH_PAYFORWARD,/// Twitch paying forward of gifts.
158         TWITCH_CROWDCHANT,/// Twitch message with some emotes.
159         TWITCH_ANNOUNCEMENT, /// Twitch channel announcement.
160         TWITCH_DIRECTCHEER, /// Twitch direct cheer with real currency.
161         TWITCH_INTRO,     /// Twitch, someone introducing themselves in a channel.
162 
163         RPL_WELCOME, // = 001,          // ":Welcome to <server name> <user>"
164         RPL_YOURHOST, // = 002,         // ":Your host is <servername>, running version <version>"
165         RPL_CREATED, // = 003,          // ":This server was created <date>"
166         RPL_MYINFO, // = 004,           // "<server_name> <version> <user_modes> <chan_modes>"
167         RPL_BOUNCE, // = 005,           // CONFLICT ":Try server <server_name>, port <port_number>"
168         RPL_ISUPPORT, // = 005,         // (server information, different syntax)
169         RPL_MAP, // = 006,
170         RPL_MAPEND, // = 007,
171         RPL_SNOMASK, // = 008,          // Server notice mask (hex)
172         RPL_STATMEMTOT, // = 009,
173         //RPL_BOUNCE, // = 010,         // CONFLICT "<hostname> <port> :<info>",
174         //RPL_STATMEM, // = 010,        // deprecated, prefer THISSERVERINSTEAD
175         RPL_YOURCOOKIE, // = 014,
176         //RPL_MAP, // = 015,
177         RPL_MAPMORE, // = 016,
178         //RPL_MAPEND, // = 017,
179         RPL_HELLO, // = 020,
180         RPL_APASSWARN_SET, // = 030,
181         RPL_APASSWARN_SECRET, // = 031,
182         RPL_APASSWARN_CLEAR, // = 032,
183         RPL_YOURID, // = 042,           // <nickname> <id> :your unique ID
184         RPL_SAVENICK, // = 043,         // Sent to the client when their nickname was forced to change due to a collision
185         RPL_ATTEMPTINGJUNC, // = 050,
186         RPL_ATTEMPTINGREROUTE, // = 051,
187 
188         RPL_REMOTEISUPPORT, // 105,
189 
190         RPL_TRACELINK, // = 200,        // "Link <version & debug level> <destination> <next server>"
191         RPL_TRACECONNECTING, // = 201,  // "Try. <class> <server>"
192         RPL_TRACEHANDSHAKE, // = 202,   // "H.S. <class> <server>"
193         RPL_TRACEUNKNOWN, // = 203,     // "???? <class> [<client IP address in dot form>]"
194         RPL_TRACEOPERATOR, // = 204,    // "Oper <class> <nick>"
195         RPL_TRACEUSER, // = 205,        // "User <class> <nick>"
196         RPL_TRACESERVER, // = 206,      // "Serv <class> <int>S <int>C <server> <nick!user|*!*>@<host|server>"
197         RPL_TRACESERVICE, // = 207,     // "Service <class> <name> <type> <active_type>
198         RPL_TRACENEWTYPE, // = 208,     // "<newtype> 0 <client name>"
199         RPL_TRACECLASS, // = 209,       // "Class <class> <count>"
200         RPL_TRACERECONNECT, // = 210,   // CONFLICT
201         RPL_STATSHELP, // = 210,        // CONFLICT
202         RPL_STATS, // = 210,            // Used instead of having multiple stats numerics
203         RPL_STATSLINKINFO, // = 211,    // "<linkname> <sendq> <sent messages> <sent bytes> <received messages> <received bytes> <time open>"
204         RPL_STATSCOMMAND, // = 212,     // "<command> <count>"
205         RPL_STATSCLINE, // = 213,       // "C <host> * <name> <port> <class>"
206         RPL_STATSNLINE, // = 214,       // "N <host> * <name> <port> <class>"
207         RPL_STATSILINE, // = 215,       // "I <host> * <host> <port> <class>"
208         RPL_STATSKLINE, // = 216,       // "K <host> * <username> <port> <class>"
209         RPL_STATSPLINE, // = 217,       // CONFLICT
210         RPL_STATSQLINE, // = 217,
211         RPL_STATSYLINE, // = 218        // "Y <class> <ping frequency> <connect frequency> <max sendq>"
212         RPL_ENDOFSTATS, // = 219,       // "<stats letter> :End of /STATS report"
213         RPL_STATSBLINE, // = 220,       // CONFLICT
214         RPL_STATSWLINE, // = 220,       // CONFLICT
215         //RPL_STATSPLINE, // = 220,
216         RPL_UMODEIS, // = 221,          // "<user mode string>"
217         //RPL_STATSBLINE, // = 222,     // CONFLICT
218         RPL_SQLINE_NICK, // = 222,      // CONFLICT
219         RPL_CODEPAGE, // = 222,         // CONFLICT
220         RPL_STATSJLINE, // = 222,       // CONFLICT
221         RPL_MODLIST, // = 222,
222         RPL_STATSGLINE, // = 223,       // CONFLICT
223         RPL_CHARSET, // = 223,          // CONFLICT
224         RPL_STATSELINE, // = 223,
225         RPL_STATSTLINE, // = 224,       // CONFLICT
226         RPL_STATSFLINE, // = 224,
227         //RPL_STATSELINE, // = 225,     // CONFLICT
228         RPL_STATSZLINE, // = 225,       // CONFLICT
229         RPL_STATSCLONE, // = 225,       // CONFLICT
230         RPL_STATSDLINE, // = 225,
231         //RPL_STATSNLINE, // = 226,     // CONFLICT
232         RPL_STATSALINE, // = 226,       // CONFLICT
233         RPL_STATSCOUNT, // = 226,
234         //RPL_STATSGLINE, // = 227,     // CONFLICT
235         RPL_STATSVLINE, // = 227,       // CONFLICT
236         //RPL_STATSBLINE, // = 227,
237         RPL_STATSBANVER, // = 228,      // CONFLICT
238         //RPL_STATSQLINE, // = 228,
239         RPL_STATSSPAMF, // = 229,
240         RPL_STATSEXCEPTTKL, // = 230,
241         RPL_SERVICEINFO, // = 231,      // (reserved numeric)
242         RPL_RULES, // = 232,            // CONFLICT
243         RPL_ENDOFSERVICES, // = 232,    // (reserved numeric)
244         RPL_SERVICE, // = 233,          // (reserved numeric)
245         RPL_SERVLIST, // = 234,         // (reserved numeric)
246         RPL_SERVLISTEND, // = 235,      // (reserved numeric)
247         RPL_STATSVERBOSE, // = 236,     // Verbose server list?
248         RPL_STATSENGINE, // = 237,      // Engine name?
249         //RPL_STATSFLINE, // = 238,     // Feature lines?
250         RPL_STATSIAUTH, // = 239,
251         RPL_STATSXLINE, // = 240,       // CONFLICT
252         //RPL_STATSVLINE, // = 240,
253         RPL_STATSLLINE, // = 241,       // "L <hostmask> * <servername> <maxdepth>"
254         RPL_STATSUPTIME, // = 242,      // ":Server Up %d days %d:%02d:%02d"
255         RPL_STATSOLINE, // = 243,       // "O <hostmask> * <name>"
256         RPL_STATSHLINE, // = 244,       // "H <hostmask> * <servername>"
257         //RPL_STATSTLINE, // = 245,     // CONFLICT
258         RPL_STATSSLINE, // = 245,
259         RPL_STATSSERVICE, // = 246,     // CONFLICT
260         //RPL_STATSTLINE, // = 246,     // CONFLICT
261         RPL_STATSULINE, // = 246,       // CONFLICT
262         RPL_STATSPING, // = 246,
263         //RPL_STATSXLINE, // = 247,     // CONFLICT
264         //RPL_STATSGLINE, // = 247,     // CONFLICT
265         //RPL_STATSBLINE, // = 247,
266         RPL_STATSDEFINE, // = 248,      // CONFLICT
267         //RPL_STATSULINE, // = 248,
268         RPL_STATSDEBUG, // = 249,       // CONFLICT
269         //RPL_STATSULINE, // = 249,
270         //RPL_STATSDLINE, // = 250,     // CONFLICT
271         RPL_STATSCONN, // = 250,
272         RPL_LUSERCLIENT, // = 251,      // ":There are <integer> users and <integer> invisible on <integer> servers"
273         RPL_LUSEROP, // = 252,          // "<integer> :operator(s) online"
274         RPL_LUSERUNKNOWN, // = 253,     // "<integer> :unknown connection(s)"
275         RPL_LUSERCHANNELS, // = 254,    // "<integer> :channels formed"
276         RPL_LUSERME, // = 255,          // ":I have <integer> clients and <integer> servers"
277         RPL_ADMINME, // = 256,          // "<server> :Administrative info"
278         RPL_ADMINLOC1, // = 257,        // ":<admin info>"
279         RPL_ADMINLOC2, // = 258,        // ":<admin info>"
280         RPL_ADMINEMAIL, // = 259,       // ":<admin info>"
281         RPL_TRACELOG, // = 261,         // "File <logfile> <debug level>"
282         RPL_TRACEPING, // = 262,        // CONFLICT
283         RPL_TRACEEND, // = 262,         // "<server_name> <version>[.<debug_level>] :<info>"
284         RPL_TRYAGAIN, // = 263,         // "<command> :<info>"
285         RPL_USINGSSL, // = 264,
286         RPL_LOCALUSERS, // = 265,       // Also known as RPL_CURRENT_LOCAL
287         RPL_GLOBALUSERS, // = 266,      // Also known as RPL_CURRENT_GLOBAL
288         RPL_START_NETSTAT, // = 267,
289         RPL_NETSTAT, // = 268,
290         RPL_END_NETSTAT, // = 269,
291         RPL_MAPUSERS, // = 270,         // CONFLICT
292         RPL_PRIVS, // = 270,
293         RPL_SILELIST, // = 271,
294         RPL_ENDOFSILELIST, // = 272,
295         RPL_NOTIFY, // = 273,
296         RPL_STATSDELTA, // = 274,       // CONFLICT
297         RPL_ENDNOTIFY, // = 274,
298         //RPL_USINGSSL, // = 275,       // CONFLICT
299         //RPL_STATSDLINE, // = 275,
300         RPL_VCHANEXIST, // = 276,       // CONFLICT
301         RPL_WHOISCERTFP, // = 276,      // CONFLICT
302         RPL_STATSRLINE, // = 276,
303         RPL_VCHANLIST, // = 277,
304         RPL_VCHANHELP, // = 278,
305         RPL_GLIST, // = 280
306         RPL_ENDOFGLIST, // = 281,       // CONFLICT
307         RPL_ACCEPTLIST, // = 281,
308         RPL_JUPELIST, // = 282,         // CONFLICT
309         RPL_ENDOFACCEPT, // = 282,
310         RPL_ENDOFJUPELIST, // = 283,    // CONFLICT
311         RPL_ALIST, // = 283,
312         RPL_FEATURE, // = 284,          // CONFLICT
313         RPL_ENDOFALIST, // = 284,
314         RPL_CHANINFO_HANDLE, // = 285,  // CONFLICT
315         RPL_NEWHOSTIS, // = 285,        // CONFLICT
316         RPL_GLIST_HASH, // = 285,
317         RPL_CHKHEAD, // = 286,          // CONFLICT
318         RPL_CHANINFO_USERS, // = 286,
319         RPL_CHANUSER, // = 287          // CONFLICT
320         RPL_CHANINFO_CHOPS, // = 287,
321         RPL_PATCHHEAD, // = 288,        // CONFLICT
322         RPL_CHANINFO_VOICES, // = 288,
323         RPL_PATCHCON, // = 289,         // CONFLICT
324         RPL_CHANINFO_AWAY, // = 289,
325         RPL_CHANINFO_HELPHDR, // = 290, // CONFLICT
326         RPL_DATASTR, // = 290,          // CONFLICT
327         RPL_HELPHDR, // = 290,          // CONFLICT
328         RPL_CHANINFO_OPERS, // = 290,
329         RPL_ENDOFCHECK, // = 291,       // CONFLICT
330         RPL_HELPOP, // = 291,           // CONFLICT
331         RPL_CHANINFO_BANNED, // = 291,
332         ERR_SEARCHNOMATCH, // = 292  ,  // CONFLICT
333         RPL_HELPTLR, // = 292,          // CONFLICT
334         RPL_CHANINFO_BANS, // = 292,
335         RPL_HELPHLP, // = 293,          // CONFLICT
336         RPL_CHANINFO_INVITE, // = 293,
337         RPL_HELPFWD, // = 294,          // CONFLICT
338         RPL_CHANINFO_INVITES, // = 294,
339         RPL_HELPIGN, // = 295,          // CONFLICT
340         RPL_CHANINFO_KICK, // = 295,
341         RPL_CHANINFO_KICKS, // = 296,
342         RPL_END_CHANINFO, // = 299,
343 
344         RPL_NONE, // = 300,             // Dummy reply number. Not used.
345         RPL_AWAY, // = 301              // "<nick> :<away message>"
346         RPL_USERHOST, // = 302          // ":[<reply>{<space><reply>}]"
347         RPL_ISON, // = 303,             // ":[<nick> {<space><nick>}]"
348         RPL_SYNTAX, // = 304,           // CONFLICT
349         RPL_TEXT, // = 304,
350         RPL_UNAWAY, // = 305,           // ":You are no longer marked as being away"
351         RPL_NOWAWAY, // = 306,          // ":You have been marked as being away"
352         RPL_SUSERHOST, // = 307,        // CONFLICT
353         RPL_USERIP, // = 307,           // CONFLICT
354         RPL_WHOISREGNICK, // = 307      // <nickname> :has identified for this nick
355         RPL_WHOISADMIN, // = 308,       // CONFLICT
356         RPL_RULESSTART, // = 308,       // CONFLICT
357         RPL_NOTIFYACTION, // = 308,
358         RPL_WHOISHELPER, // = 309,      // CONFLICT
359         RPL_ENDOFRULES, // = 309,       // CONFLICT
360         //RPL_WHOISADMIN, // = 309,     // CONFLICT
361         RPL_NICKTRACE, // = 309,
362         RPL_WHOISSERVICE, // = 310,     // CONFLICT
363         RPL_WHOISHELPOP, // = 310,      // CONFLICT
364         RPL_WHOISSVCMSG, // = 310,
365         RPL_WHOISUSER, // = 311,        // "<nick> <user> <host> * :<real name>"
366         RPL_WHOISSERVER, // = 312,      // "<nick> <server> :<server info>"
367         RPL_WHOISOPERATOR, // = 313,    // "<nick> :is an IRC operator"
368         RPL_WHOWASUSER, // = 314,       // "<nick> <user> <host> * :<real name>"
369         RPL_ENDOFWHO, // = 315,         // "<name> :End of /WHO list"
370         RPL_WHOISPRIVDEAF, // = 316     // CONFLICT
371         RPL_WHOISCHANOP, // = 316,      // (reserved numeric)
372         RPL_WHOISIDLE, // = 317,        // "<nick> <integer> :seconds idle"
373         RPL_ENDOFWHOIS, // = 318,       // "<nick> :End of /WHOIS list"
374         RPL_WHOISCHANNELS, // = 319,    // "<nick> :{[@|+]<channel><space>}"
375         RPL_WHOISVIRT, // = 320,        // CONFLICT
376         RPL_WHOIS_HIDDEN, // = 320,     // CONFLICT
377         RPL_WHOISSPECIAL, // = 320,
378         RPL_LISTSTART, // = 321,        // "Channel :Users  Name"
379         RPL_LIST, // = 322,             // "<channel> <# visible> :<topic>"
380         RPL_LISTEND, // = 323,          // ":End of /LIST"
381         RPL_CHANNELMODEIS, // = 324,    // "<channel> <mode> <mode params>"
382         RPL_WHOISWEBIRC, // = 325,      // CONFLICT
383         RPL_CHANNELMLOCKIS, // = 325,   // CONFLICT
384         RPL_UNIQOPIS, // = 325,         // CONFLICT
385         RPL_CHANNELPASSIS, // = 325,
386         RPL_NOCHANPASS, // = 326,
387         //RPL_WHOISHOST, // = 327,        // CONFLICT
388         RPL_CHPASSUNKNOWN, // = 327,
389         RPL_CHANNEL_URL, // = 328       // "http://linux.chat"
390         RPL_CREATIONTIME, // = 329,
391         RPL_WHOWAS_TIME, // = 330,      // CONFLICT
392         RPL_WHOISACCOUNT, // = 330      // "<nickname> <account> :is logged in as"
393         RPL_NOTOPIC, // = 331,          // "<channel> :No topic is set"
394         RPL_TOPIC, // = 332,            // "<channel> :<topic>"
395         RPL_TOPICWHOTIME, // = 333,     // "#channel user!~ident@address 1476294377"
396         RPL_COMMANDSYNTAX, // = 334,    // CONFLICT
397         RPL_LISTSYNTAX, // = 334,       // CONFLICT
398         RPL_LISTUSAGE, // = 334,
399         RPL_WHOISTEXT, // = 335,        // CONFLICT
400         RPL_WHOISACCOUNTONLY, // = 335, // CONFLICT
401         RPL_WHOISBOT, // = 335,         // "<nick> <othernick> :is a Bot on <server>"
402         //RPL_WHOISBOT, // = 336,       // CONFLICT
403         RPL_INVITELIST, // = 336,
404         //RPL_WHOISTEXT, // = 337,      // CONFLICT
405         RPL_ENDOFINVITELIST, // = 337,  // CONFLICT
406         RPL_CHANPASSOK, // = 338,       // CONFLICT
407         RPL_WHOISACTUALLY, // = 338,
408         RPL_WHOISMARKS, // = 339,       // CONFLICT
409         RPL_BADCHANPASS, // = 339,
410         //RPL_USERIP, // = 340,
411         RPL_INVITING, // = 341,         // "<channel> <nick>"
412         RPL_SUMMONING, // = 342,        // "<user> :Summoning user to IRC"
413         RPL_WHOISKILL, // = 343,
414         RPL_REOPLIST, // = 344,         // "<channel> <mask>"
415         RPL_ENDOFREOPLIST, // = 345,    // CONFLICT
416         RPL_INVITED, // = 345,
417         //RPL_INVITELIST, // = 346,
418         //RPL_ENDOFINVITELIST, // = 347,
419         RPL_EXCEPTLIST, // = 348,
420         RPL_ENDOFEXCEPTLIST, // = 349,
421         RPL_VERSION, // = 351,          // "<version>.<debuglevel> <server> :<comments>"
422         RPL_WHOREPLY, // = 352,         // "<channel> <user> <host> <server> <nick> | <H|G>[*][@|+] :<hopcount> <real name>"
423         RPL_NAMREPLY, // = 353,         // "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
424         RPL_WHOSPCRPL, // = 354,
425         RPL_NAMREPLY_, // = 355,
426         //RPL_MAP, // = 357,
427         //RPL_MAPMORE, // = 358,
428         //RPL_MAPEND, // = 359,
429         RPL_WHOWASREAL, // = 360,
430         RPL_KILLDONE, // = 361,         // (reserved numeric)
431         RPL_CLOSING, // = 362,          // (reserved numeric)
432         RPL_CLOSEEND, // = 363,         // (reserved numeric)
433         RPL_LINKS, // = 364,            // "<mask> <server> :<hopcount> <server info>"
434         RPL_ENDOFLINKS, // = 365,       // "<mask> :End of /LINKS list"
435         RPL_ENDOFNAMES, // = 366,       // "<channel> :End of /NAMES list"
436         RPL_BANLIST, // = 367,          // "<channel> <banid>"
437         RPL_ENDOFBANLIST, // = 368,     // "<channel> :End of channel ban list"
438         RPL_ENDOFWHOWAS, // = 369,      // "<nick> :End of WHOWAS"
439         RPL_INFO, // = 371,             // ":<string>"
440         RPL_MOTD, // = 372,             // ":- <text>"
441         RPL_INFOSTART, // = 373,        // (reserved numeric)
442         RPL_ENDOFINFO, // = 374,        //  ":End of /INFO list"
443         RPL_MOTDSTART, // = 375,        // ":- <server> Message of the day - "
444         RPL_ENDOFMOTD, // = 376,        // ":End of /MOTD command"
445         RPL_SPAM, // = 377,             // CONFLICT
446         RPL_KICKEXPIRED, // = 377,
447         RPL_BANEXPIRED, // = 378,       // CONFLICT
448         //RPL_MOTD, // = 378,           // CONFLICT
449         RPL_WHOISHOST, // = 378         // <nickname> :is connecting from *@<address> <ip>
450         RPL_KICKLINKED, // = 379,       // CONFLICT
451         RPL_WHOWASIP, // = 379,         // CONFLICT
452         RPL_WHOISMODES, // = 379,       // <nickname> :is using modes <modes>
453         RPL_YOURHELPER, // = 380,       // CONFLICT
454         RPL_BANLINKED, // = 380,
455         RPL_YOUREOPER, // = 381,        // ":You are now an IRC operator"
456         RPL_REHASHING, // = 382,        // "<config file> :Rehashing"
457         RPL_YOURESERVICE, // = 383,
458         RPL_MYPORTIS, // = 384,
459         RPL_NOTOPERANYMORE, // = 385,
460         RPL_IRCOPS, // = 386,           // CONFLICT
461         RPL_IRCOPSHEADER, // = 386,     // CONFLICT
462         RPL_RSACHALLENGE, // = 386,     // CONFLICT
463         RPL_QLIST, // = 386,
464         RPL_ENDOFIRCOPS, // = 387,      // CONFLICT
465         //RPL_IRCOPS, // = 387,         // CONFLICT
466         RPL_ENDOFQLIST, // = 387,
467         //RPL_ENDOFIRCOPS, // = 388,    // CONFLICT
468         //RPL_ALIST, // = 388,
469         //RPL_ENDOFALIST, // = 389,
470         RPL_TIME, // = 391,             // "<server> :<string showing server's local time>"
471         RPL_USERSTART, // = 392,        // ":UserID   Terminal  Host"
472         RPL_USERS, // = 393,            // ":%-8s %-9s %-8s"
473         RPL_ENDOFUSERS, // = 394,       // ":End of users"
474         RPL_NOUSERS, // = 395,          // ":Nobody logged in"
475         RPL_VISIBLEHOST, // = 396,      // CONFLICT
476         RPL_HOSTHIDDEN, // = 396,       // <nickname> <host> :is now your hidden host
477 
478         ERR_UNKNOWNERROR, // = 400,
479         ERR_NOSUCHNICK, // = 401,       // "<nickname> :No such nick/channel"
480         ERR_NOSUCHSERVER, // = 402,     // "<server name> :No such server"
481         ERR_NOSUCHCHANNEL, // = 403,    // "<channel name> :No such channel"
482         ERR_CANNOTSENDTOCHAN, // = 404, // "<channel name> :Cannot send to channel"
483         ERR_TOOMANYCHANNELS, // = 405,  // "<channel name> :You have joined too many channels"
484         ERR_WASNOSUCHNICK, // = 406,    // "<nickname> :There was no such nickname"
485         ERR_TOOMANYTARGETS, // = 407,   // "<target> :Duplicate recipients. No message delivered""
486         ERR_NOCTRLSONCHAN, // = 408,    // CONFLICT
487         ERR_NOCOLORSONCHAN, // = 408,   // CONFLICT
488         ERR_NOSUCHSERVICE, // = 408,
489         ERR_NOORIGIN, // = 409,         // ":No origin specified"
490         ERR_INVALIDCAPCMD, // = 410,
491         ERR_NORECIPIENT, // = 411,      // ":No recipient given (<command>)"
492         ERR_NOTEXTTOSEND, // = 412,     // ":No text to send"
493         ERR_NOTOPLEVEL, // = 413,       // "<mask> :No toplevel domain specified"
494         ERR_WILDTOPLEVEL, // = 414,     // "<mask> :Wildcard in toplevel domain"
495         ERR_BADMASK, // = 415,
496         ERR_QUERYTOOLONG, // = 416,     // CONFLICT
497         ERR_TOOMANYMATCHES, // = 416,
498         ERR_INPUTTOOLONG, // = 417,
499         ERR_LENGTHTRUNCATED, // = 419,
500         ERR_UNKNOWNCOMMAND, // = 421,   // "<command> :Unknown command"
501         ERR_NOMOTD, // = 422,           // ":MOTD File is missing"
502         ERR_NOADMININFO, // = 423,      // "<server> :No administrative info available"
503         ERR_FILEERROR, // = 424,        // ":File error doing <file op> on <file>"
504         ERR_NOOPERMOTD, // = 425,
505         ERR_TOOMANYAWAY, // = 429,
506         ERR_EVENTNICKCHANGE, // = 430,
507         ERR_NONICKNAMEGIVEN, // = 431,  // ":No nickname given"
508         ERR_ERRONEOUSNICKNAME, // = 432,// "<nick> :Erroneus nickname"
509         ERR_NICKNAMEINUSE, // = 433,    // "<nick> :Nickname is already in use"
510         ERR_SERVICENAMEINUSE, // = 434, //CONFLICT
511         ERR_NORULES, // = 434,
512         ERR_SERVICECONFUSED, // = 435   // CONFLICT
513         ERR_BANONCHAN, // = 435         // <nickname> <target nickname> <channel> :Cannot change nickname while banned on channel
514         ERR_NICKCOLLISION, // = 436,    // "<nick> :Nickname collision KILL"
515         ERR_BANNICKCHANGE, // = 437,    // CONFLICT
516         ERR_UNAVAILRESOURCE, // = 437,  // <nickname> <channel> :Nick/channel is temporarily unavailable
517         ERR_DEAD, // = 438,             // CONFLICT
518         ERR_NICKTOOFAST, // = 438,
519         ERR_TARGETTOOFAST, // = 439,    // <nickname> :This server has anti-spambot mechanisms enabled.
520         ERR_SERVICESDOWN, // = 440,
521         ERR_USERNOTINCHANNEL, // = 441, // "<nick> <channel> :They aren't on that channel"
522         ERR_NOTONCHANNEL, // = 442,     // "<channel> :You're not on that channel"
523         ERR_USERONCHANNEL, // = 443,    // "<user> <channel> :is already on channel"
524         ERR_NOLOGIN, // = 444,          // "<user> :User not logged in"
525         ERR_SUMMONDISABLED, // = 445,   // ":SUMMON has been disabled"
526         ERR_USERSDISABLED, // = 446,    // ":USERS has been disabled"
527         ERR_NONICKCHANGE, // = 447,
528         ERR_FORBIDDENCHANNEL, // = 448,
529         ERR_NOTIMPLEMENTED, // = 449,
530         ERR_NOTREGISTERED, // = 451,    // ":You have not registered"
531         ERR_IDCOLLISION, // = 452,
532         ERR_NICKLOST, // = 453,
533         //ERR_IDCOLLISION, // = 455     // <nickname> :Your username <nickname> contained the invalid character(s) <characters> and has been changed to mrkaufma. Please use only the characters 0-9 a-z A-Z _ - or . in your username. Your username is the part before the @ in your email address.
534         ERR_HOSTILENAME, // = 455,
535         ERR_ACCEPTFULL, // = 456
536         ERR_ACCEPTEXIST, // = 457,
537         ERR_ACCEPTNOT, // = 458,
538         ERR_NOHIDING, // = 459,
539         ERR_NOTFORHALFOPS, // = 460,
540         ERR_NEEDMOREPARAMS, // = 461,   // "<command> :Not enough parameters"
541         ERR_ALREADYREGISTERED, // = 462,// ":You may not reregister"
542         ERR_NOPERMFORHOST, // = 463,    // ":Your host isn't among the privileged"
543         ERR_PASSWDMISMATCH, // = 464,   // ":Password incorrect"
544         ERR_YOUREBANNEDCREEP, // = 465, // ":You are banned from this server"
545         ERR_YOUWILLBEBANNED, // = 466   // (reserved numeric)
546         ERR_KEYSET, // = 467,           // "<channel> :Channel key already set"
547         ERR_NOCODEPAGE, // = 468,       // CONFLICT
548         ERR_ONLYSERVERSCANCHANGE, // = 468,// CONFLICT
549         ERR_INVALIDUSERNAME, // = 468,
550         ERR_LINKSET, // = 469,
551         ERR_7BIT, // = 470,             // CONFLICT
552         ERR_KICKEDFROMCHAN, // = 470,   // CONFLICT
553         ERR_LINKCHANNEL, // = 470       // <#original> <#new> :Forwarding to another channel
554         ERR_CHANNELISFULL, // = 471,    // "<channel> :Cannot join channel (+l)"
555         ERR_UNKNOWNMODE, // = 472,      // "<char> :is unknown mode char to me"
556         ERR_INVITEONLYCHAN, // = 473,   // "<channel> :Cannot join channel (+i)"
557         ERR_BANNEDFROMCHAN, // = 474,   // "<channel> :Cannot join channel (+b)"
558         ERR_BADCHANNELKEY, // = 475,    // "<channel> :Cannot join channel (+k)"
559         ERR_BADCHANMASK, // = 476,      // (reserved numeric)
560         ERR_NOCHANMODES, // = 477       // CONFLICT
561         ERR_NEEDREGGEDNICK, // = 477    // <nickname> <channel> :Cannot join channel (+r) - you need to be identified with services
562         ERR_BANLISTFULL, // = 478,
563         ERR_NOCOLOR, // = 479,          // CONFLICT
564         ERR_BADCHANNAME, // = 479,
565         ERR_LINKFAIL, // = 479,         // CONFLICT
566         ERR_THROTTLE, // = 480,         // CONFLICT
567         ERR_NOWALLOP, // = 480,         // CONFLICT
568         ERR_SSLONLYCHAN, // = 480,      // CONFLICT
569         ERR_NOULINE, // = 480,          // CONFLICT
570         ERR_CANNOTKNOCK, // = 480,
571         ERR_NOPRIVILEGES, // = 481,     // ":Permission Denied- You're not an IRC operator"
572         ERR_CHANOPRIVSNEEDED, // = 482, // [sic] "<channel> :You're not channel operator"
573         ERR_CANTKILLSERVER, // = 483,   // ":You cant kill a server!"
574         ERR_ATTACKDENY, // = 484,       // CONFLICT
575         ERR_DESYNC, // = 484,           // CONFLICT
576         ERR_ISCHANSERVICE, // = 484,    // CONFLICT
577         ERR_RESTRICTED, // = 484,
578         ERR_BANNEDNICK, // = 485,       // CONFLICT
579         ERR_CHANBANREASON, // = 485,    // CONFLICT
580         ERR_KILLDENY, // = 485,         // CONFLICT
581         ERR_CANTKICKADMIN, // = 485,    // CONFLICT
582         ERR_ISREALSERVICE, // = 485,    // CONFLICT
583         ERR_UNIQPRIVSNEEDED, // = 485,
584         ERR_ACCOUNTONLY, // = 486,      // CONFLICT
585         ERR_RLINED, // = 486,           // CONFLICT
586         ERR_HTMDIABLED, // = 486,       // CONFLICT
587         ERR_NONONREG, // = 486,
588         ERR_NONONSSL, // = 487,         // CONFLICT
589         ERR_NOTFORUSERS, // = 487,      // CONFLICT
590         ERR_CHANTOORECENT, // = 487,    // CONFLICT
591         ERR_MSGSERVICES, // = 487       // <nickname> :Error! "/msg NickServ" is no longer supported. Use "/msg NickServ@services.dal.net" or "/NickServ" instead.
592         ERR_HTMDISABLED, // = 488,      // CONFLICT
593         ERR_NOSSL, // = 488,            // CONFLICT
594         ERR_TSLESSCHAN, // = 488,
595         ERR_VOICENEEDED, // = 489,      // CONFLICT
596         ERR_SECUREONLYCHAN, // = 489,
597         ERR_NOSWEAR, // = 490,          // CONFLICT
598         ERR_ALLMUSTSSL, // = 490,
599         ERR_NOOPERHOST, // = 491,       // ":No O-lines for your host"
600         ERR_CANNOTSENDTOUSER, // = 492, // CONFLICT
601         ERR_NOCTCP, // = 492,           // CONFLICT
602         ERR_NOTCP, // = 492,            // CONFLICT
603         ERR_NOSERVICEHOST, // = 492,    // (reserved numeric)
604         ERR_NOSHAREDCHAN, // = 493      // CONFLICT
605         ERR_NOFEATURE, // = 493,
606         ERR_OWNMODE, // = 494,          // CONFLICT
607         ERR_BADFEATVALUE, // = 494,
608         ERR_DELAYREJOIN, // = 495,      // CONFLICT
609         ERR_BADLOGTYPE, // = 495,
610         ERR_BADLOGSYS, // = 496,
611         ERR_BADLOGVALUE, // = 497,
612         ERR_ISOPERLCHAN, // = 498,
613         ERR_CHANOWNPRIVNEEDED, // = 499,
614 
615         ERR_NOREHASHPARAM, // = 500,    // CONFLICT
616         ERR_TOOMANYJOINS, // = 500,
617         ERR_UNKNOWNSNOMASK, // = 501,   // CONFLICT
618         ERR_UMODEUNKNOWNFLAG, // = 501, // ":Unknown MODE flag"
619         ERR_USERSDONTMATCH, // = 502,   // ":Cant change mode for other users"
620         ERR_VWORLDWARN, // = 503,       // CONFLICT
621         ERR_GHOSTEDCLIENT, // = 503,
622         ERR_USERNOTONSERV, // = 504,
623         ERR_SILELISTFULL, // = 511,
624         ERR_NOSUCHGLINE, // = 512,      // CONFLICT
625         ERR_TOOMANYWATCH, // = 512,
626         //ERR_BADPING, // 513,          // CONFLICT
627         ERR_NEEDPONG, // = 513,         // <nickname> :To connect type /QUOTE PONG <number>
628         ERR_NOSUCHJUPE, // = 514,       // CONFLICT
629         ERR_TOOMANYDCC, // = 514,       // CONFLICT
630         ERR_INVALID_ERROR, // = 514,
631         ERR_BADEXPIRE, // = 515,
632         ERR_DONTCHEAT, // = 516,
633         ERR_DISABLED, // = 517,
634         ERR_NOINVITE, // = 518,         // CONFLICT
635         ERR_LONGMASK, // = 518,
636         ERR_ADMONLY, // = 519,          // CONFLICT
637         ERR_TOOMANYUSERS, // = 519,
638         ERR_WHOTRUNC, // = 520,         // CONFLICT
639         ERR_MASKTOOWIDE, // = 520,      // CONFLICT
640         ERR_OPERONLY, // = 520,
641         //ERR_NOSUCHGLINE, // = 521,    // CONFLICT
642         ERR_LISTSYNTAX, // = 521,
643         ERR_WHOSYNTAX, // = 522,
644         ERR_WHOLIMEXCEED, // = 523,
645         ERR_OPERSPVERIFY, // = 524,     // CONFLICT
646         ERR_QUARANTINED, // = 524,      // CONFLICT
647         ERR_HELPNOTFOUND, // = 524,
648         ERR_INVALIDKEY, // = 525,       // CONFLICT
649         ERR_REMOTEPFX, // = 525,
650         ERR_PFXUNROUTABLE, // = 526,
651         ERR_CANTSENDTOUSER, // = 531,
652         ERR_BADHOSTMASK, // = 550,
653         ERR_HOSTUNAVAIL, // = 551,
654         ERR_USINGSLINE, // = 552,
655         ERR_STATSSLINE, // = 553,
656         ERR_NOTLOWEROPLEVEL, // = 560,
657         ERR_NOTMANAGER, // = 561,
658         ERR_CHANSECURED, // = 562,
659         ERR_UPASSSET, // = 563,
660         ERR_UPASSNOTSET, // = 564,
661         ERR_NOMANAGER, // = 566,
662         ERR_UPASS_SAME_APASS, // = 567,
663         RPL_NOMOTD, // = 568            // CONFLICT
664         ERR_LASTERROR, // = 568,
665         RPL_REAWAY, // = 597,
666         RPL_GONEAWAY, // = 598,
667         RPL_NOTAWAY, // = 599,
668 
669         RPL_LOGON, // = 600,
670         RPL_LOGOFF, // = 601,
671         RPL_WATCHOFF, // = 602,
672         RPL_WATCHSTAT, // = 603,
673         RPL_NOWON, // = 604,
674         RPL_NOWFF, // = 605,
675         RPL_WATCHLIST, // = 606,
676         RPL_ENDOFWATCHLIST, // = 607,
677         RPL_WATCHCLEAR, // = 608,
678         RPL_NOWISAWAY, // = 609,
679         RPL_ISOPER, // = 610            // CONFLICT
680         //RPL_MAPMORE, // = 610,
681         RPL_ISLOCOP, // = 611,
682         RPL_ISNOTOPER, // = 612,
683         RPL_ENDOFISOPER, // = 613,
684         //RPL_MAPMORE, // = 615,        // CONFLICT
685         //RPL_WHOISMODES, // = 615,
686         //RPL_WHOISHOST, // = 616,
687         RPL_WHOISSSLFP, // = 617,       // CONFLICT
688         //RPL_WHOISBOT, // = 617,       // CONFLICT
689         RPL_DCCSTATUS, // = 617,
690         RPL_DCCLIST, // = 618,
691         RPL_WHOWASHOST, // = 619,       // CONFLICT
692         RPL_ENDOFDCCLIST, // = 619,
693         //RPL_RULESSTART, // = 620,     // CONFLICT
694         RPL_DCCINFO, // = 620,
695         //RPL_RULES, // = 621,
696         //RPL_ENDOFRULES, // = 622,
697         //RPL_MAPMORE, // = 623,
698         RPL_OMOTDSTART, // = 624,
699         RPL_OMOTD, // = 625
700         RPL_ENDOFO, // = 626,
701         RPL_SETTINGS, // = 630,
702         RPL_ENDOFSETTINGS, // = 631,
703         RPL_DUMPING, // = 640,
704         RPL_DUMPRPL, // = 641,
705         RPL_EODUMP, // = 642,
706         RPL_SPAMCMDFWD, // = 659,
707         RPL_TRACEROUTE_HOP, // = 660,
708         RPL_TRACEROUTE_START, // = 661,
709         RPL_MODECHANGEWARN, // = 662,
710         RPL_CHANREDIR, // = 663,
711         RPL_SERVMODEIS, // = 664,
712         RPL_OTHERUMODEIS, // = 665,
713         RPL_ENDOF_GENERIC, // = 666,
714         RPL_WHOWASDETAILS, // = 670,    // CONFLICT
715         RPL_STARTTLS, // = 670,
716         RPL_WHOISSECURE, // = 671       // "<nickname> :is using a secure connection"
717         RPL_UNKNOWNMODES, // = 672,     // CONFLICT
718         RPL_WHOISREALIP, // 672,
719         RPL_CANNOTSETMODES, // = 673,
720         RPL_WHOISYOURID, // = 674,
721         RPL_LUSERSTAFF, // = 678,
722         RPL_TIMEONSERVERIS, // = 679,
723         RPL_NETWORKS, // = 682,
724         RPL_YOURLANGUAGEIS, // = 687,
725         RPL_LANGUAGE, // = 688,
726         RPL_WHOISSTAFF, // = 689,
727         RPL_WHOISLANGUAGE, // = 690,
728         ERR_STARTTLS, // = 691,
729 
730         //RPL_MODLIST, // = 702,        // CONFLICT
731         RPL_COMMANDS, // = 702,
732         RPL_ENDOFMODLIST, // = 703,     // CONFLICT
733         RPL_COMMANDSEND, // = 703,
734         RPL_HELPSTART, // = 704         // <nickname> index :Help topics available to users:
735         RPL_HELPTXT, // = 705           // <nickname> index :ACCEPT\tADMIN\tAWAY\tCHALLENGE
736         RPL_ENDOFHELP, // = 706         // <nickname> index :End of /HELP.
737         ERR_TARGCHANGE, // = 707,
738         RPL_ETRACEFULL, // = 708,
739         RPL_ETRACE, // = 709,
740         RPL_KNOCK, // = 710,
741         RPL_KNOCKDLVR, // = 711,
742         ERR_TOOMANYKNOCK, // = 712,
743         ERR_CHANOPEN, // = 713,
744         ERR_KNOCKONCHAN, // = 714,
745         ERR_KNOCKDISABLED, // = 715,    // CONFLICT
746         ERR_TOOMANYINVITE, // = 715,    // CONFLICT
747         RPL_INVITETHROTTLE, // = 715,
748         RPL_TARGUMODEG, // = 716,
749         RPL_TARGNOTIFY, // = 717,
750         RPL_UMODEGMSG, // = 718,
751         //RPL_OMOTDSTART, // = 720
752         //RPL_OMOTD, // = 721,
753         RPL_ENDOFOMOTD, // = 722,
754         ERR_NOPRIVS, // = 723,
755         RPL_TESTMASK, // = 724,
756         RPL_TESTLINE, // = 725,
757         RPL_NOTESTLINE, // = 726,
758         RPL_TESTMASKGECOS, // = 727,
759         RPL_QUIETLIST, // = 728,        // also 344 on oftc
760         RPL_ENDOFQUIETLIST, // = 729,
761         RPL_MONONLINE, // = 730,
762         RPL_MONOFFLINE, // = 731,
763         RPL_MONLIST, // = 732,
764         RPL_ENDOFMONLIST, // = 733,
765         ERR_MONLISTFULL, // = 734,
766         RPL_RSACHALLENGE2, // = 740,
767         RPL_ENDOFRSACHALLENGE2, // = 741,
768         ERR_MLOCKRESTRICTED, // = 742,
769         ERR_INVALIDBAN, // = 743,
770         ERR_TOPICLOCK, // = 744,
771         RPL_SCANMATCHED, // = 750,
772         RPL_SCANUMODES, // = 751,
773         RPL_ETRACEEND, // = 759,
774         RPL_WHOISKEYVALUE, // = 760,
775         RPL_KEYVALUE, // = 761,
776         RPL_METADATAEND, // = 762,
777         ERR_METADATALIMIT, // = 764,
778         ERR_TARGETINVALID, // = 765,
779         ERR_NOMATCHINGKEY, // = 766,
780         ERR_KEYINVALID, // = 767,
781         ERR_KEYNOTSET, // = 768,
782         ERR_KEYNOPERMISSION, // = 769,
783         RPL_XINFO, // = 771,
784         RPL_XINFOSTART, // = 773
785         RPL_XINFOEND, // = 774,
786 
787         RPL_CHECK, // = 802,
788 
789         RPL_LOGGEDIN, // = 900,         // <nickname>!<ident>@<address> <nickname> :You are now logged in as <nickname>
790         RPL_LOGGEDOUT, // = 901,
791         ERR_NICKLOCKED, // = 902,
792         RPL_SASLSUCCESS, // = 903,      // :cherryh.freenode.net 903 kameloso^ :SASL authentication successful
793         ERR_SASLFAIL, // = 904,         // :irc.rizon.no 904 kameloso^^ :SASL authentication failed"
794         ERR_SASLTOOLONG, // = 905,
795         ERR_SASLABORTED, // = 906,      // :orwell.freenode.net 906 kameloso^ :SASL authentication aborted
796         ERR_SASLALREADY, // = 907,
797         RPL_SASLMECHS, // = 908,
798         ERR_WORDFILTERED, // = 936,
799         ERR_CANTUNLOADMODULE, // = 972, // CONFLICT
800         ERR_CANNOTDOCOMMAND, // = 972,
801         ERR_CANNOTCHANGEUMODE, // = 973,
802         ERR_CANTLOADMODULE, // = 974,   // CONFLICT
803         ERR_CANNOTCHANGECHANMODE, // = 974,
804         ERR_CANNOTCHANGESERVERMODE, // = 975,// CONFLICT
805         //ERR_LASTERROR, // = 975,      // CONFLICT
806         RPL_LOADEDMODULE, // = 975,
807         ERR_CANNOTSENDTONICK, // = 976,
808         ERR_UNKNOWNSERVERMODE, // = 977,
809         ERR_SERVERMODELOCK, // = 979,
810         ERR_BADCHARENCODING, // = 980,
811         ERR_TOOMANYLANGUAGES, // = 981,
812         ERR_NOLANGUAGE, // = 982,
813         ERR_TEXTTOOSHORT, // = 983,
814 
815         ERR_NUMERIC_ERR, // = 999
816     }
817 
818     /*
819         /++
820             Run this to generate the Type[n] map.
821 
822             HAS NOT BEEN TESTED IN YEARS. There's been no need for it.
823             Don't expect it to work.
824          +/
825         void generateTypenums()
826         {
827             import std.regex;
828             import std.algorithm;
829             import std.stdio;
830 
831             enum pattern = r" *([A-Z0-9_]+),? [/= ]* ([0-9]+),?.*";
832             static engine = ctRegex!pattern;
833             string[1024] arr;
834 
835             foreach (const line; s.splitter("\n"))
836             {
837                 auto hits = line.matchFirst(engine);
838                 if (hits.length < 2) continue;
839 
840                 try
841                 {
842                     size_t idx = hits[2].to!size_t;
843                     if (arr[idx] != typeof(arr[idx]).init) stderr.writeln("DUPLICATE! ", idx);
844                     arr[idx] = hits[1];
845                 }
846                 catch (Exception e)
847                 {
848                     //writeln(e.msg, ": ", line);
849                 }
850             }
851 
852             writeln("static immutable Type[1024] typenums =\n[");
853 
854             foreach (immutable i, const val; arr)
855             {
856                 if (!val.length) continue;
857 
858                 writefln("    %-3d : Type.%s,", i, val);
859             }
860 
861             writeln("];");
862         }
863     */
864 
865     /++
866         The event type, signifying what *kind* of event this is.
867      +/
868     Type type;
869 
870     /++
871         The raw IRC string, untouched.
872      +/
873     @Hidden string raw;
874 
875     /++
876         The name of whoever (or whatever) sent this event.
877      +/
878     IRCUser sender;
879 
880     /++
881         The channel the event transpired in, or is otherwise related to.
882      +/
883     string channel;
884 
885     /++
886         The target user of the event.
887      +/
888     IRCUser target;
889 
890     /++
891         The main body of text of the event.
892      +/
893     string content;
894 
895     /++
896         Auxiliary string array.
897      +/
898     string[numAuxStrings] aux;
899 
900     /++
901         IRCv3 message tags attached to this event
902      +/
903     string tags;
904 
905     /++
906         With a numeric event, the number of the event type.
907      +/
908     uint num;
909 
910     /++
911         Count array.
912      +/
913     Nullable!long[numCounts] count;
914 
915     /++
916         A timestamp of when the event transpired.
917      +/
918     @Hidden long time;
919 
920     /++
921         What errors occurred during parsing, if any.
922      +/
923     string errors;
924 
925     version(TwitchSupport)
926     {
927         /++
928             The Twitch emotes in the message, if any.
929          +/
930         string emotes;
931 
932         /++
933             The Twitch ID of this message.
934          +/
935         string id;
936     }
937 }
938 
939 
940 // IRCServer
941 /++
942     Aggregate of all information and state pertaining to the connected IRC
943     server. Some fields are transient on a per-connection basis and should not
944     be serialised.
945  +/
946 struct IRCServer
947 {
948     /++
949         Server daemons, or families of server programs.
950 
951         Many daemons handle some events slightly differently than others do, and
952         by tracking which daemon the server is running we can apply the
953         differences and always have an appropriate tables of events.
954      +/
955     enum Daemon
956     {
957         unset,      /// Unset or invalid daemon.
958         unknown,    /// Reported but unknown daemon.
959 
960         unreal,
961         solanum,
962         inspircd,
963         bahamut,
964         ratbox,
965         u2,
966         hybrid,
967         snircd,
968         rizon,
969         undernet,
970         ircdseven,
971         twitch,
972         bsdunix,
973         mfvx,
974 
975         charybdis,
976         sorircd,
977 
978         ircu,
979         aircd,
980         rfc1459,
981         rfc2812,
982         nefarious,
983         rusnet,
984         austhex,
985         ircnet,
986         ptlink,
987         ultimate,
988         anothernet,
989         bdqircd,
990         chatircd,
991         irch,
992         ithildin,
993     }
994 
995     /++
996         Case mappings used by an IRC server.
997 
998         These decide how case-insensitivity works.
999      +/
1000     enum CaseMapping
1001     {
1002         /// The lowercase of `[A-Z]` is `[a-z]`.
1003         ascii,
1004         /// `ascii`, plus the lowercase of `[]\^` is `{}|~`.
1005         rfc1459,
1006         /// `rfc1459`, except no `^` for `~`.
1007         strict_rfc1459,
1008     }
1009 
1010     /++
1011         Server address (or IP).
1012      +/
1013     string address;
1014 
1015     /++
1016         The port to connect to, usually `6667`-`6669`.
1017      +/
1018     ushort port;
1019 
1020     @Unserialisable
1021     {
1022         /++
1023             The server daemon family the server is running.
1024          +/
1025         Daemon daemon;
1026 
1027         /++
1028             Server network string, like Freenode, QuakeNet, Rizon.
1029          +/
1030         string network;
1031 
1032         /++
1033             The reported daemon, with version.
1034          +/
1035         string daemonstring;
1036 
1037         /++
1038             The IRC server address handed to us by the round robin pool.
1039          +/
1040         string resolvedAddress;
1041 
1042         /++
1043             Max nickname length as per IRC specs, but not the de facto standard.
1044          +/
1045         uint maxNickLength = 9;
1046 
1047         /++
1048             Max channel name length as per IRC specs, or as reported.
1049          +/
1050         uint maxChannelLength = 200;
1051 
1052         /++
1053             A = Mode that adds or removes a nick or address to a list.
1054                 Always has a parameter.
1055          +/
1056         string aModes; // = "eIbq";
1057 
1058         /++
1059             B = Mode that changes a setting and always has a parameter.
1060          +/
1061         string bModes; // = "k";
1062 
1063         /++
1064             C = Mode that changes a setting and only has a parameter when set.
1065          +/
1066         string cModes; // = "flj";
1067 
1068         /++
1069             D = Mode that changes a setting and never has a parameter.
1070          +/
1071         string dModes; // = "CFLMPQScgimnprstz";
1072 
1073         /++
1074             Prefix characters by mode character; `o` by `@`, `v` by `+`, etc.
1075          +/
1076         char[char] prefixchars;
1077 
1078         /++
1079             Character channel mode prefixes (`o`, `v`, `h`, ...)
1080          +/
1081         string prefixes;
1082 
1083         /++
1084             Supported channel prefix characters, as announced by the server in
1085             the [dialect.defs.IRCEvent.Type.RPL_ISUPPORT|RPL_ISUPPORT]` event,
1086             before the MOTD.
1087          +/
1088         string chantypes = "#";
1089 
1090         /++
1091             The current case mapping, dictating how case-insensitivity works.
1092          +/
1093         CaseMapping caseMapping;
1094 
1095         /++
1096             `EXTBAN` prefix character.
1097          +/
1098         char extbanPrefix = '$';
1099 
1100         /++
1101             `EXTBAN` types.
1102          +/
1103         string extbanTypes;
1104 
1105         /++
1106             The modechar for mode exceptions.
1107          +/
1108         char exceptsChar = 'e';
1109 
1110         /++
1111             The modechar for invite exceptions.
1112          +/
1113         char invexChar = 'I';
1114 
1115         /++
1116             Contents of the [IRCEvent.Type.RPL_ISUPPORT|RPL_ISUPPORT] response(s).
1117          +/
1118         string supports;
1119     }
1120 
1121     /++
1122         Constructor.
1123      +/
1124     auto this(
1125         const string address,
1126         const ushort port) pure @safe nothrow @nogc
1127     {
1128         this.address = address;
1129         this.port = port;
1130     }
1131 }
1132 
1133 
1134 // IRCUser
1135 /++
1136     An aggregate of fields representing a single user on IRC.
1137 
1138     Instances of these should not survive a disconnect and reconnect; they are
1139     transient on a per-connection basis and should not be serialised.
1140  +/
1141 struct IRCUser
1142 {
1143     /++
1144         The user's nickname.
1145      +/
1146     string nickname;
1147 
1148     version(BotElements)
1149     {
1150         /++
1151             Classifiers; roles which a user is one of.
1152          +/
1153         enum Class
1154         {
1155             unset,      /// Unknown, yet to be determined.
1156             blacklist,  /// A blacklisted user.
1157             anyone,     /// Any user.
1158             registered, /// A user registered with services.
1159             whitelist,  /// A whitelisted user.
1160             elevated,   /// An elevated user, something in between `whitelist` and `operator`.
1161             operator,   /// A user enjoying operator (or moderator) privileges.
1162             staff,      /// The owner of a channel; an elevated user but not a full administrator.
1163             admin,      /// An administrator, in a bot-like context.
1164         }
1165 
1166         /++
1167             User classifier.
1168          +/
1169         Class class_;
1170     }
1171 
1172     /++
1173         The user's GECOS/"real name".
1174      +/
1175     string realName;
1176 
1177     /++
1178         The user's IDENT identification.
1179      +/
1180     string ident;
1181 
1182     /++
1183         The reported user address, which may be a cloak.
1184      +/
1185     string address;
1186 
1187     /++
1188         Services account name (to `NickServ`, `AuthServ`, `Q`, etc).
1189      +/
1190     string account;
1191 
1192     /++
1193         Timestamp when the user was last modified.
1194      +/
1195     @Hidden long updated;
1196 
1197     version(TwitchSupport)
1198     {
1199         // Twitch has some extra features.
1200 
1201         /++
1202             The alternate "display name" of the user.
1203          +/
1204         string displayName;
1205 
1206         /++
1207             The Twitch badges this user has.
1208          +/
1209         string badges;
1210 
1211         /++
1212             The Twitch colour (RRGGBB) to tint the user's nickname with.
1213          +/
1214         string colour;
1215 
1216         /++
1217             The Twitch ID of this user's account.
1218          +/
1219         uint id;
1220     }
1221 
1222     /++
1223         Create a new [IRCUser] based on a `*!*@*` mask string.
1224      +/
1225     this(string userstring) pure @safe
1226     {
1227         import std.format : formattedRead;
1228 
1229         userstring.formattedRead("%s!%s@%s", nickname, ident, address);
1230         if (nickname == "*") nickname = string.init;
1231         if (ident == "*") ident = string.init;
1232         if (address == "*") address = string.init;
1233     }
1234 
1235     ///
1236     unittest
1237     {
1238         {
1239             immutable user = IRCUser("nickname!~ident@address");
1240             assert((user.nickname == "nickname"), user.nickname);
1241             assert((user.ident == "~ident"), user.ident);
1242             assert((user.address == "address"), user.address);
1243         }
1244         {
1245             immutable user = IRCUser("*!~ident@address");
1246             assert(!user.nickname.length, user.nickname);
1247             assert((user.ident == "~ident"), user.ident);
1248             assert((user.address == "address"), user.address);
1249         }
1250         {
1251             immutable user = IRCUser("*!*@*");
1252             assert(!user.nickname.length, user.nickname);
1253             assert(!user.ident.length, user.ident);
1254             assert(!user.address.length, user.address);
1255         }
1256     }
1257 
1258     /++
1259         Create a new [IRCUser] inheriting passed `nickname`, `ident`, and
1260         `address` strings.
1261      +/
1262     auto this(
1263         const string nickname,
1264         const string ident,
1265         const string address) pure @safe nothrow @nogc
1266     {
1267         this.nickname = nickname;
1268         this.ident = ident;
1269         this.address = address;
1270     }
1271 
1272     /++
1273         Makes an educated guess that a sender is a server.
1274 
1275         Returns:
1276             `true` if the sender nickname and/or address looks to be a server's,
1277             `false` if not.
1278      +/
1279     auto isServer() const @property pure @safe nothrow @nogc
1280     {
1281         import std.string : indexOf;
1282         return !nickname.length && (address.indexOf('.') != -1);
1283     }
1284 
1285     ///
1286     @safe unittest
1287     {
1288         IRCUser user;
1289 
1290         user.address = "blah.freenode.net";
1291         assert(user.isServer);
1292 
1293         user.nickname = "foo";
1294         assert(!user.isServer);
1295 
1296         user.nickname = string.init;
1297         user.address = "nodots";
1298         assert(!user.isServer);  // unsure what to even make of no-dot addresses
1299 
1300         // :kameloso MODE kameloso :+i
1301         user.nickname = "kameloso";
1302         user.address = string.init;
1303         assert(!user.isServer);
1304     }
1305 
1306     /++
1307         Compares two [IRCUser]s with each other, ignoring members considered to
1308         be extra or optional.
1309 
1310         Params:
1311             that = Second user to compare this one with.
1312 
1313         Returns:
1314             `true` if the users match, `false` if not.
1315      +/
1316     auto opEquals(const IRCUser that) const pure @safe nothrow @nogc
1317     {
1318         return
1319             (this.nickname == that.nickname) &&
1320             (this.ident == that.ident) &&
1321             (this.address == that.address);
1322     }
1323 
1324     /++
1325         Produces a hash for this [IRCUser].
1326 
1327         Returns:
1328             A hash.
1329      +/
1330     auto toHash() const pure @safe
1331     {
1332         return this.hostmask.hashOf;
1333     }
1334 
1335     // toString
1336     /++
1337         Formats this [IRCUser] into a hostmask representing its values.
1338         Stores the result in the passed output range sink.
1339 
1340         Params:
1341             sink = Output range sink to save the hostmask string to.
1342      +/
1343     void toString(Sink)(auto ref Sink sink) const @safe
1344     {
1345         import std.format : formattedWrite;
1346 
1347         immutable nickname = this.nickname.length ? this.nickname : "*";
1348         immutable ident = this.ident.length ? this.ident : "*";
1349         immutable address = this.address.length ? this.address : "*";
1350 
1351         sink.formattedWrite("%s!%s@%s", nickname, ident, address);
1352     }
1353 
1354     // hostmask
1355     /++
1356         Formats this [IRCUser] into a hostmask representing its values.
1357         Merely wraps [toString] and returns a newly allocated string.
1358 
1359         Returns:
1360             A hostmask "*!*@*" string.
1361      +/
1362     string hostmask() pure @safe const
1363     {
1364         import std.array : Appender;
1365 
1366         Appender!(char[]) sink;
1367         sink.reserve(nickname.length + ident.length + address.length + 5);  // for ! and @ as well as ***
1368 
1369         this.toString(sink);
1370         return sink.data;
1371     }
1372 
1373     ///
1374     @safe unittest
1375     {
1376         {
1377             const user = IRCUser("nickname", "ident", "address.tld");
1378             immutable hostmask = user.hostmask;
1379             assert((hostmask == "nickname!ident@address.tld"), hostmask);
1380         }
1381         {
1382             const user = IRCUser("nickname", string.init, "address.tld");
1383             immutable hostmask = user.hostmask;
1384             assert((hostmask == "nickname!*@address.tld"), hostmask);
1385         }
1386         {
1387             const user = IRCUser(string.init, string.init, "address.tld");
1388             immutable hostmask = user.hostmask;
1389             assert((hostmask == "*!*@address.tld"), hostmask);
1390         }
1391         {
1392             const IRCUser user;
1393             immutable hostmask = user.hostmask;
1394             assert((hostmask == "*!*@*"), hostmask);
1395         }
1396     }
1397 }
1398 
1399 
1400 // Typenums
1401 /++
1402     Reverse mappings of *numerics* to [IRCEvent.Type|Type]s.
1403 
1404     One `base` table that covers most cases, and then specialised arrays for
1405     different server daemons, to meld into `base` for a union of the two
1406     (or more). This speeds up translation greatly and allows us to have
1407     different mappings for different daemons.
1408  +/
1409 struct Typenums
1410 {
1411 private:
1412     alias Type = IRCEvent.Type;
1413 
1414 public:
1415     /++
1416         Default mappings.
1417      +/
1418     static immutable Type[1024] base =
1419     [
1420         1   : Type.RPL_WELCOME,
1421         2   : Type.RPL_YOURHOST,
1422         3   : Type.RPL_CREATED,
1423         4   : Type.RPL_MYINFO,
1424         5   : Type.RPL_ISUPPORT,
1425         6   : Type.RPL_MAP,
1426         7   : Type.RPL_MAPEND,
1427         8   : Type.RPL_SNOMASK,
1428         9   : Type.RPL_STATMEMTOT,
1429         10  : Type.THISSERVERINSTEAD,  // was Type.RPL_STATMEM
1430         14  : Type.RPL_YOURCOOKIE,
1431         15  : Type.RPL_MAP,
1432         16  : Type.RPL_MAPMORE,
1433         17  : Type.RPL_MAPEND,
1434         20  : Type.RPL_HELLO,
1435         30  : Type.RPL_APASSWARN_SET,
1436         31  : Type.RPL_APASSWARN_SECRET,
1437         32  : Type.RPL_APASSWARN_CLEAR,
1438         42  : Type.RPL_YOURID,
1439         43  : Type.RPL_SAVENICK,
1440         50  : Type.RPL_ATTEMPTINGJUNC,
1441         51  : Type.RPL_ATTEMPTINGREROUTE,
1442         105 : Type.RPL_REMOTEISUPPORT,
1443         200 : Type.RPL_TRACELINK,
1444         201 : Type.RPL_TRACECONNECTING,
1445         202 : Type.RPL_TRACEHANDSHAKE,
1446         203 : Type.RPL_TRACEUNKNOWN,
1447         204 : Type.RPL_TRACEOPERATOR,
1448         205 : Type.RPL_TRACEUSER,
1449         206 : Type.RPL_TRACESERVER,
1450         207 : Type.RPL_TRACESERVICE,
1451         208 : Type.RPL_TRACENEWTYPE,
1452         209 : Type.RPL_TRACECLASS,
1453         210 : Type.RPL_STATS,
1454         211 : Type.RPL_STATSLINKINFO,
1455         212 : Type.RPL_STATSCOMMAND,
1456         213 : Type.RPL_STATSCLINE,
1457         214 : Type.RPL_STATSNLINE,
1458         215 : Type.RPL_STATSILINE,
1459         216 : Type.RPL_STATSKLINE,
1460         217 : Type.RPL_STATSQLINE,
1461         218 : Type.RPL_STATSYLINE,
1462         219 : Type.RPL_ENDOFSTATS,
1463         220 : Type.RPL_STATSPLINE,
1464         221 : Type.RPL_UMODEIS,
1465         222 : Type.RPL_MODLIST,
1466         223 : Type.RPL_STATSELINE,
1467         224 : Type.RPL_STATSFLINE,
1468         225 : Type.RPL_STATSDLINE,
1469         226 : Type.RPL_STATSCOUNT,
1470         227 : Type.RPL_STATSBLINE,
1471         228 : Type.RPL_STATSQLINE,
1472         229 : Type.RPL_STATSSPAMF,
1473         230 : Type.RPL_STATSEXCEPTTKL,
1474         231 : Type.RPL_SERVICEINFO,
1475         232 : Type.RPL_ENDOFSERVICES,
1476         233 : Type.RPL_SERVICE,
1477         234 : Type.RPL_SERVLIST,
1478         235 : Type.RPL_SERVLISTEND,
1479         236 : Type.RPL_STATSVERBOSE,
1480         237 : Type.RPL_STATSENGINE,
1481         238 : Type.RPL_STATSFLINE,
1482         239 : Type.RPL_STATSIAUTH,
1483         240 : Type.RPL_STATSVLINE,
1484         241 : Type.RPL_STATSLLINE,
1485         242 : Type.RPL_STATSUPTIME,
1486         243 : Type.RPL_STATSOLINE,
1487         244 : Type.RPL_STATSHLINE,
1488         245 : Type.RPL_STATSSLINE,
1489         246 : Type.RPL_STATSPING,
1490         247 : Type.RPL_STATSBLINE,
1491         248 : Type.RPL_STATSULINE,
1492         249 : Type.RPL_STATSULINE,
1493         250 : Type.RPL_STATSCONN,
1494         251 : Type.RPL_LUSERCLIENT,
1495         252 : Type.RPL_LUSEROP,
1496         253 : Type.RPL_LUSERUNKNOWN,
1497         254 : Type.RPL_LUSERCHANNELS,
1498         255 : Type.RPL_LUSERME,
1499         256 : Type.RPL_ADMINME,
1500         257 : Type.RPL_ADMINLOC1,
1501         258 : Type.RPL_ADMINLOC2,
1502         259 : Type.RPL_ADMINEMAIL,
1503         261 : Type.RPL_TRACELOG,
1504         262 : Type.RPL_TRACEEND,
1505         263 : Type.RPL_TRYAGAIN,
1506         264 : Type.RPL_USINGSSL,
1507         265 : Type.RPL_LOCALUSERS,
1508         266 : Type.RPL_GLOBALUSERS,
1509         267 : Type.RPL_START_NETSTAT,
1510         268 : Type.RPL_NETSTAT,
1511         269 : Type.RPL_END_NETSTAT,
1512         270 : Type.RPL_PRIVS,
1513         271 : Type.RPL_SILELIST,
1514         272 : Type.RPL_ENDOFSILELIST,
1515         273 : Type.RPL_NOTIFY,
1516         274 : Type.RPL_ENDNOTIFY,
1517         275 : Type.RPL_STATSDLINE,
1518         276 : Type.RPL_STATSRLINE,
1519         277 : Type.RPL_VCHANLIST,
1520         278 : Type.RPL_VCHANHELP,
1521         280 : Type.RPL_GLIST,
1522         281 : Type.RPL_ACCEPTLIST,
1523         282 : Type.RPL_ENDOFACCEPT,
1524         283 : Type.RPL_ALIST,
1525         284 : Type.RPL_ENDOFALIST,
1526         285 : Type.RPL_GLIST_HASH,
1527         286 : Type.RPL_CHANINFO_USERS,
1528         287 : Type.RPL_CHANINFO_CHOPS,
1529         288 : Type.RPL_CHANINFO_VOICES,
1530         289 : Type.RPL_CHANINFO_AWAY,
1531         290 : Type.RPL_CHANINFO_OPERS,
1532         291 : Type.RPL_CHANINFO_BANNED,
1533         292 : Type.RPL_CHANINFO_BANS,
1534         293 : Type.RPL_CHANINFO_INVITE,
1535         294 : Type.RPL_CHANINFO_INVITES,
1536         295 : Type.RPL_CHANINFO_KICK,
1537         296 : Type.RPL_CHANINFO_KICKS,
1538         299 : Type.RPL_END_CHANINFO,
1539         300 : Type.RPL_NONE,
1540         301 : Type.RPL_AWAY,
1541         302 : Type.RPL_USERHOST,
1542         303 : Type.RPL_ISON,
1543         304 : Type.RPL_TEXT,
1544         305 : Type.RPL_UNAWAY,
1545         306 : Type.RPL_NOWAWAY,
1546         307 : Type.RPL_WHOISREGNICK,
1547         308 : Type.RPL_NOTIFYACTION,
1548         309 : Type.RPL_NICKTRACE,
1549         310 : Type.RPL_WHOISSVCMSG,
1550         311 : Type.RPL_WHOISUSER,
1551         312 : Type.RPL_WHOISSERVER,
1552         313 : Type.RPL_WHOISOPERATOR,
1553         314 : Type.RPL_WHOWASUSER,
1554         315 : Type.RPL_ENDOFWHO,
1555         316 : Type.RPL_WHOISCHANOP,
1556         317 : Type.RPL_WHOISIDLE,
1557         318 : Type.RPL_ENDOFWHOIS,
1558         319 : Type.RPL_WHOISCHANNELS,
1559         320 : Type.RPL_WHOISSPECIAL,
1560         321 : Type.RPL_LISTSTART,
1561         322 : Type.RPL_LIST,
1562         323 : Type.RPL_LISTEND,
1563         324 : Type.RPL_CHANNELMODEIS,
1564         325 : Type.RPL_CHANNELPASSIS,
1565         326 : Type.RPL_NOCHANPASS,
1566         327 : Type.RPL_CHPASSUNKNOWN,
1567         328 : Type.RPL_CHANNEL_URL,
1568         329 : Type.RPL_CREATIONTIME,
1569         330 : Type.RPL_WHOISACCOUNT,
1570         331 : Type.RPL_NOTOPIC,
1571         332 : Type.RPL_TOPIC,
1572         333 : Type.RPL_TOPICWHOTIME,
1573         334 : Type.RPL_LISTUSAGE,
1574         335 : Type.RPL_WHOISBOT,
1575         336 : Type.RPL_INVITELIST,
1576         337 : Type.RPL_ENDOFINVITELIST,
1577         338 : Type.RPL_WHOISACTUALLY,
1578         339 : Type.RPL_BADCHANPASS,
1579         340 : Type.RPL_USERIP,
1580         341 : Type.RPL_INVITING,
1581         342 : Type.RPL_SUMMONING,
1582         343 : Type.RPL_WHOISKILL,
1583         345 : Type.RPL_INVITED,
1584         346 : Type.RPL_INVITELIST,
1585         347 : Type.RPL_ENDOFINVITELIST,
1586         348 : Type.RPL_EXCEPTLIST,
1587         349 : Type.RPL_ENDOFEXCEPTLIST,
1588         351 : Type.RPL_VERSION,
1589         352 : Type.RPL_WHOREPLY,
1590         353 : Type.RPL_NAMREPLY,
1591         354 : Type.RPL_WHOSPCRPL,
1592         355 : Type.RPL_NAMREPLY_,
1593         357 : Type.RPL_MAP,
1594         358 : Type.RPL_MAPMORE,
1595         359 : Type.RPL_MAPEND,
1596         360 : Type.RPL_WHOWASREAL,
1597         361 : Type.RPL_KILLDONE,
1598         362 : Type.RPL_CLOSING,
1599         363 : Type.RPL_CLOSEEND,
1600         364 : Type.RPL_LINKS,
1601         365 : Type.RPL_ENDOFLINKS,
1602         366 : Type.RPL_ENDOFNAMES,
1603         367 : Type.RPL_BANLIST,
1604         368 : Type.RPL_ENDOFBANLIST,
1605         369 : Type.RPL_ENDOFWHOWAS,
1606         371 : Type.RPL_INFO,
1607         372 : Type.RPL_MOTD,
1608         373 : Type.RPL_INFOSTART,
1609         374 : Type.RPL_ENDOFINFO,
1610         375 : Type.RPL_MOTDSTART,
1611         376 : Type.RPL_ENDOFMOTD,
1612         377 : Type.RPL_KICKEXPIRED,
1613         378 : Type.RPL_WHOISHOST,
1614         379 : Type.RPL_WHOISMODES,
1615         380 : Type.RPL_BANLINKED,
1616         381 : Type.RPL_YOUREOPER,
1617         382 : Type.RPL_REHASHING,
1618         383 : Type.RPL_YOURESERVICE,
1619         384 : Type.RPL_MYPORTIS,
1620         385 : Type.RPL_NOTOPERANYMORE,
1621         386 : Type.RPL_QLIST,
1622         387 : Type.RPL_ENDOFQLIST,
1623         388 : Type.RPL_ALIST,
1624         389 : Type.RPL_ENDOFALIST,
1625         391 : Type.RPL_TIME,
1626         392 : Type.RPL_USERSTART,
1627         393 : Type.RPL_USERS,
1628         394 : Type.RPL_ENDOFUSERS,
1629         395 : Type.RPL_NOUSERS,
1630         396 : Type.RPL_HOSTHIDDEN,
1631         400 : Type.ERR_UNKNOWNERROR,
1632         401 : Type.ERR_NOSUCHNICK,
1633         402 : Type.ERR_NOSUCHSERVER,
1634         403 : Type.ERR_NOSUCHCHANNEL,
1635         404 : Type.ERR_CANNOTSENDTOCHAN,
1636         405 : Type.ERR_TOOMANYCHANNELS,
1637         406 : Type.ERR_WASNOSUCHNICK,
1638         407 : Type.ERR_TOOMANYTARGETS,
1639         408 : Type.ERR_NOSUCHSERVICE,
1640         409 : Type.ERR_NOORIGIN,
1641         410 : Type.ERR_INVALIDCAPCMD,
1642         411 : Type.ERR_NORECIPIENT,
1643         412 : Type.ERR_NOTEXTTOSEND,
1644         413 : Type.ERR_NOTOPLEVEL,
1645         414 : Type.ERR_WILDTOPLEVEL,
1646         415 : Type.ERR_BADMASK,
1647         416 : Type.ERR_TOOMANYMATCHES,
1648         417 : Type.ERR_INPUTTOOLONG,
1649         419 : Type.ERR_LENGTHTRUNCATED,
1650         421 : Type.ERR_UNKNOWNCOMMAND,
1651         422 : Type.ERR_NOMOTD,
1652         423 : Type.ERR_NOADMININFO,
1653         424 : Type.ERR_FILEERROR,
1654         425 : Type.ERR_NOOPERMOTD,
1655         429 : Type.ERR_TOOMANYAWAY,
1656         430 : Type.ERR_EVENTNICKCHANGE,
1657         431 : Type.ERR_NONICKNAMEGIVEN,
1658         432 : Type.ERR_ERRONEOUSNICKNAME,
1659         433 : Type.ERR_NICKNAMEINUSE,
1660         434 : Type.ERR_NORULES,
1661         435 : Type.ERR_BANONCHAN,
1662         436 : Type.ERR_NICKCOLLISION,
1663         437 : Type.ERR_UNAVAILRESOURCE,
1664         438 : Type.ERR_NICKTOOFAST,
1665         439 : Type.ERR_TARGETTOOFAST,
1666         440 : Type.ERR_SERVICESDOWN,
1667         441 : Type.ERR_USERNOTINCHANNEL,
1668         442 : Type.ERR_NOTONCHANNEL,
1669         443 : Type.ERR_USERONCHANNEL,
1670         444 : Type.ERR_NOLOGIN,
1671         445 : Type.ERR_SUMMONDISABLED,
1672         446 : Type.ERR_USERSDISABLED,
1673         447 : Type.ERR_NONICKCHANGE,
1674         448 : Type.ERR_FORBIDDENCHANNEL,
1675         449 : Type.ERR_NOTIMPLEMENTED,
1676         451 : Type.ERR_NOTREGISTERED,
1677         452 : Type.ERR_IDCOLLISION,
1678         453 : Type.ERR_NICKLOST,
1679         455 : Type.ERR_HOSTILENAME,
1680         456 : Type.ERR_ACCEPTFULL,
1681         457 : Type.ERR_ACCEPTEXIST,
1682         458 : Type.ERR_ACCEPTNOT,
1683         459 : Type.ERR_NOHIDING,
1684         460 : Type.ERR_NOTFORHALFOPS,
1685         461 : Type.ERR_NEEDMOREPARAMS,
1686         462 : Type.ERR_ALREADYREGISTERED,
1687         463 : Type.ERR_NOPERMFORHOST,
1688         464 : Type.ERR_PASSWDMISMATCH,
1689         465 : Type.ERR_YOUREBANNEDCREEP,
1690         466 : Type.ERR_YOUWILLBEBANNED,
1691         467 : Type.ERR_KEYSET,
1692         468 : Type.ERR_INVALIDUSERNAME,
1693         469 : Type.ERR_LINKSET,
1694         470 : Type.ERR_LINKCHANNEL,
1695         471 : Type.ERR_CHANNELISFULL,
1696         472 : Type.ERR_UNKNOWNMODE,
1697         473 : Type.ERR_INVITEONLYCHAN,
1698         474 : Type.ERR_BANNEDFROMCHAN,
1699         475 : Type.ERR_BADCHANNELKEY,
1700         476 : Type.ERR_BADCHANMASK,
1701         477 : Type.ERR_NEEDREGGEDNICK,
1702         478 : Type.ERR_BANLISTFULL,
1703         479 : Type.ERR_BADCHANNAME,
1704         480 : Type.ERR_CANNOTKNOCK,
1705         481 : Type.ERR_NOPRIVILEGES,
1706         482 : Type.ERR_CHANOPRIVSNEEDED,
1707         483 : Type.ERR_CANTKILLSERVER,
1708         484 : Type.ERR_RESTRICTED,
1709         485 : Type.ERR_UNIQPRIVSNEEDED,
1710         486 : Type.ERR_NONONREG,
1711         487 : Type.ERR_MSGSERVICES,
1712         488 : Type.ERR_TSLESSCHAN,
1713         489 : Type.ERR_SECUREONLYCHAN,
1714         490 : Type.ERR_ALLMUSTSSL,
1715         491 : Type.ERR_NOOPERHOST,
1716         492 : Type.ERR_NOSERVICEHOST,
1717         493 : Type.ERR_NOFEATURE,
1718         494 : Type.ERR_BADFEATVALUE,
1719         495 : Type.ERR_BADLOGTYPE,
1720         496 : Type.ERR_BADLOGSYS,
1721         497 : Type.ERR_BADLOGVALUE,
1722         498 : Type.ERR_ISOPERLCHAN,
1723         499 : Type.ERR_CHANOWNPRIVNEEDED,
1724         500 : Type.ERR_TOOMANYJOINS,
1725         501 : Type.ERR_UMODEUNKNOWNFLAG,
1726         502 : Type.ERR_USERSDONTMATCH,
1727         503 : Type.ERR_GHOSTEDCLIENT,
1728         504 : Type.ERR_USERNOTONSERV,
1729         511 : Type.ERR_SILELISTFULL,
1730         512 : Type.ERR_TOOMANYWATCH,
1731         513 : Type.ERR_NEEDPONG,
1732         514 : Type.ERR_INVALID_ERROR,
1733         515 : Type.ERR_BADEXPIRE,
1734         516 : Type.ERR_DONTCHEAT,
1735         517 : Type.ERR_DISABLED,
1736         518 : Type.ERR_LONGMASK,
1737         519 : Type.ERR_TOOMANYUSERS,
1738         520 : Type.ERR_OPERONLY,
1739         521 : Type.ERR_LISTSYNTAX,
1740         522 : Type.ERR_WHOSYNTAX,
1741         523 : Type.ERR_WHOLIMEXCEED,
1742         524 : Type.ERR_HELPNOTFOUND,
1743         525 : Type.ERR_REMOTEPFX,
1744         526 : Type.ERR_PFXUNROUTABLE,
1745         531 : Type.ERR_CANTSENDTOUSER,
1746         550 : Type.ERR_BADHOSTMASK,
1747         551 : Type.ERR_HOSTUNAVAIL,
1748         552 : Type.ERR_USINGSLINE,
1749         553 : Type.ERR_STATSSLINE,
1750         560 : Type.ERR_NOTLOWEROPLEVEL,
1751         561 : Type.ERR_NOTMANAGER,
1752         562 : Type.ERR_CHANSECURED,
1753         563 : Type.ERR_UPASSSET,
1754         564 : Type.ERR_UPASSNOTSET,
1755         566 : Type.ERR_NOMANAGER,
1756         567 : Type.ERR_UPASS_SAME_APASS,
1757         568 : Type.ERR_LASTERROR,
1758         597 : Type.RPL_REAWAY,
1759         598 : Type.RPL_GONEAWAY,
1760         599 : Type.RPL_NOTAWAY,
1761         600 : Type.RPL_LOGON,
1762         601 : Type.RPL_LOGOFF,
1763         602 : Type.RPL_WATCHOFF,
1764         603 : Type.RPL_WATCHSTAT,
1765         604 : Type.RPL_NOWON,
1766         605 : Type.RPL_NOWFF,
1767         606 : Type.RPL_WATCHLIST,
1768         607 : Type.RPL_ENDOFWATCHLIST,
1769         608 : Type.RPL_WATCHCLEAR,
1770         609 : Type.RPL_NOWISAWAY,
1771         610 : Type.RPL_MAPMORE,
1772         611 : Type.RPL_ISLOCOP,
1773         612 : Type.RPL_ISNOTOPER,
1774         613 : Type.RPL_ENDOFISOPER,
1775         615 : Type.RPL_WHOISMODES,
1776         616 : Type.RPL_WHOISHOST,
1777         617 : Type.RPL_DCCSTATUS,
1778         618 : Type.RPL_DCCLIST,
1779         619 : Type.RPL_ENDOFDCCLIST,
1780         620 : Type.RPL_DCCINFO,
1781         621 : Type.RPL_RULES,
1782         622 : Type.RPL_ENDOFRULES,
1783         623 : Type.RPL_MAPMORE,
1784         624 : Type.RPL_OMOTDSTART,
1785         625 : Type.RPL_OMOTD,
1786         626 : Type.RPL_ENDOFO,
1787         630 : Type.RPL_SETTINGS,
1788         631 : Type.RPL_ENDOFSETTINGS,
1789         640 : Type.RPL_DUMPING,
1790         641 : Type.RPL_DUMPRPL,
1791         642 : Type.RPL_EODUMP,
1792         659 : Type.RPL_SPAMCMDFWD,
1793         660 : Type.RPL_TRACEROUTE_HOP,
1794         661 : Type.RPL_TRACEROUTE_START,
1795         662 : Type.RPL_MODECHANGEWARN,
1796         663 : Type.RPL_CHANREDIR,
1797         664 : Type.RPL_SERVMODEIS,
1798         665 : Type.RPL_OTHERUMODEIS,
1799         666 : Type.RPL_ENDOF_GENERIC,
1800         670 : Type.RPL_STARTTLS,
1801         671 : Type.RPL_WHOISSECURE,
1802         672 : Type.RPL_WHOISREALIP,
1803         673 : Type.RPL_CANNOTSETMODES,
1804         674 : Type.RPL_WHOISYOURID,
1805         678 : Type.RPL_LUSERSTAFF,
1806         679 : Type.RPL_TIMEONSERVERIS,
1807         682 : Type.RPL_NETWORKS,
1808         687 : Type.RPL_YOURLANGUAGEIS,
1809         688 : Type.RPL_LANGUAGE,
1810         689 : Type.RPL_WHOISSTAFF,
1811         690 : Type.RPL_WHOISLANGUAGE,
1812         691 : Type.ERR_STARTTLS,
1813         702 : Type.RPL_COMMANDS,
1814         703 : Type.RPL_COMMANDSEND,
1815         704 : Type.RPL_HELPSTART,
1816         705 : Type.RPL_HELPTXT,
1817         706 : Type.RPL_ENDOFHELP,
1818         707 : Type.ERR_TARGCHANGE,
1819         708 : Type.RPL_ETRACEFULL,
1820         709 : Type.RPL_ETRACE,
1821         710 : Type.RPL_KNOCK,
1822         711 : Type.RPL_KNOCKDLVR,
1823         712 : Type.ERR_TOOMANYKNOCK,
1824         713 : Type.ERR_CHANOPEN,
1825         714 : Type.ERR_KNOCKONCHAN,
1826         715 : Type.RPL_INVITETHROTTLE,
1827         716 : Type.RPL_TARGUMODEG,
1828         717 : Type.RPL_TARGNOTIFY,
1829         718 : Type.RPL_UMODEGMSG,
1830         720 : Type.RPL_OMOTDSTART,
1831         721 : Type.RPL_OMOTD,
1832         722 : Type.RPL_ENDOFOMOTD,
1833         723 : Type.ERR_NOPRIVS,
1834         724 : Type.RPL_TESTMASK,
1835         725 : Type.RPL_TESTLINE,
1836         726 : Type.RPL_NOTESTLINE,
1837         727 : Type.RPL_TESTMASKGECOS,
1838         728 : Type.RPL_QUIETLIST,
1839         729 : Type.RPL_ENDOFQUIETLIST,
1840         730 : Type.RPL_MONONLINE,
1841         731 : Type.RPL_MONOFFLINE,
1842         732 : Type.RPL_MONLIST,
1843         733 : Type.RPL_ENDOFMONLIST,
1844         734 : Type.ERR_MONLISTFULL,
1845         740 : Type.RPL_RSACHALLENGE2,
1846         741 : Type.RPL_ENDOFRSACHALLENGE2,
1847         742 : Type.ERR_MLOCKRESTRICTED,
1848         743 : Type.ERR_INVALIDBAN,
1849         744 : Type.ERR_TOPICLOCK,
1850         750 : Type.RPL_SCANMATCHED,
1851         751 : Type.RPL_SCANUMODES,
1852         759 : Type.RPL_ETRACEEND,
1853         760 : Type.RPL_WHOISKEYVALUE,
1854         761 : Type.RPL_KEYVALUE,
1855         762 : Type.RPL_METADATAEND,
1856         764 : Type.ERR_METADATALIMIT,
1857         765 : Type.ERR_TARGETINVALID,
1858         766 : Type.ERR_NOMATCHINGKEY,
1859         767 : Type.ERR_KEYINVALID,
1860         768 : Type.ERR_KEYNOTSET,
1861         769 : Type.ERR_KEYNOPERMISSION,
1862         771 : Type.RPL_XINFO,
1863         773 : Type.RPL_XINFOSTART,
1864         774 : Type.RPL_XINFOEND,
1865         802 : Type.RPL_CHECK,
1866         900 : Type.RPL_LOGGEDIN,
1867         901 : Type.RPL_LOGGEDOUT,
1868         902 : Type.ERR_NICKLOCKED,
1869         903 : Type.RPL_SASLSUCCESS,
1870         904 : Type.ERR_SASLFAIL,
1871         905 : Type.ERR_SASLTOOLONG,
1872         906 : Type.ERR_SASLABORTED,
1873         907 : Type.ERR_SASLALREADY,
1874         908 : Type.RPL_SASLMECHS,
1875         911 : Type.ENDOFCHANNELACCLIST,
1876         960 : Type.ENDOFMODELIST,
1877         961 : Type.MODELIST,
1878         931 : Type.BOTSNOTWELCOME,
1879         926 : Type.CHANNELFORBIDDEN,
1880         936 : Type.ERR_WORDFILTERED,
1881         940 : Type.ENDOFSPAMFILTERLIST,
1882         941 : Type.SPAMFILTERLIST,
1883         945 : Type.NICKUNLOCKED,
1884         946 : Type.NICKNOTLOCKED,
1885         972 : Type.ERR_CANNOTDOCOMMAND,
1886         973 : Type.ERR_CANNOTCHANGEUMODE,
1887         974 : Type.ERR_CANNOTCHANGECHANMODE,
1888         975 : Type.RPL_LOADEDMODULE,
1889         976 : Type.ERR_CANNOTSENDTONICK,
1890         977 : Type.ERR_UNKNOWNSERVERMODE,
1891         979 : Type.ERR_SERVERMODELOCK,
1892         980 : Type.ERR_BADCHARENCODING,
1893         981 : Type.ERR_TOOMANYLANGUAGES,
1894         982 : Type.ERR_NOLANGUAGE,
1895         983 : Type.ERR_TEXTTOOSHORT,
1896         999 : Type.ERR_NUMERIC_ERR,
1897     ];
1898 
1899     /++
1900         Delta typenum mappings for servers running the `UnrealIRCd` daemon.
1901 
1902         - https://www.unrealircd.org
1903      +/
1904     static immutable Type[975] unreal =
1905     [
1906         6 : Type.RPL_MAP,
1907         7 : Type.RPL_MAPEND,
1908         210 : Type.RPL_STATSHELP,
1909         220 : Type.RPL_STATSBLINE,
1910         222 : Type.RPL_SQLINE_NICK,
1911         223 : Type.RPL_STATSGLINE,
1912         224 : Type.RPL_STATSTLINE,
1913         225 : Type.RPL_STATSELINE,
1914         226 : Type.RPL_STATSNLINE,
1915         227 : Type.RPL_STATSVLINE,
1916         228 : Type.RPL_STATSBANVER,
1917         232 : Type.RPL_RULES,
1918         247 : Type.RPL_STATSXLINE,
1919         250 : Type.RPL_STATSCONN,
1920         290 : Type.RPL_HELPHDR,
1921         291 : Type.RPL_HELPOP,
1922         292 : Type.RPL_HELPTLR,
1923         293 : Type.RPL_HELPHLP,
1924         294 : Type.RPL_HELPFWD,
1925         295 : Type.RPL_HELPIGN,
1926         307 : Type.RPL_WHOISREGNICK,
1927         308 : Type.RPL_RULESSTART,
1928         309 : Type.RPL_ENDOFRULES,
1929         310 : Type.RPL_WHOISHELPOP,
1930         320 : Type.RPL_WHOISSPECIAL,
1931         334 : Type.RPL_LISTSYNTAX,
1932         335 : Type.RPL_WHOISBOT,
1933         378 : Type.RPL_WHOISHOST,
1934         379 : Type.RPL_WHOISMODES,
1935         386 : Type.RPL_QLIST,
1936         387 : Type.RPL_ENDOFQLIST,
1937         388 : Type.RPL_ALIST,
1938         434 : Type.ERR_NORULES,
1939         435 : Type.ERR_SERVICECONFUSED,
1940         438 : Type.ERR_ONLYSERVERSCANCHANGE,
1941         470 : Type.ERR_LINKCHANNEL,
1942         477 : Type.ERR_NEEDREGGEDNICK,
1943         479 : Type.ERR_LINKFAIL,
1944         480 : Type.ERR_CANNOTKNOCK,
1945         484 : Type.ERR_ATTACKDENY,
1946         485 : Type.ERR_KILLDENY,
1947         486 : Type.ERR_HTMDISABLED,         // CONFLICT ERR_NONONREG
1948         487 : Type.ERR_NOTFORUSERS,
1949         488 : Type.ERR_HTMDISABLED,         // again?
1950         489 : Type.ERR_SECUREONLYCHAN,      // AKA ERR_SSLONLYCHAN
1951         490 : Type.ERR_ALLMUSTSSL,          // CONFLICT ERR_NOSWEAR
1952         492 : Type.ERR_NOCTCP,
1953         500 : Type.ERR_TOOMANYJOINS,
1954         518 : Type.ERR_NOINVITE,
1955         519 : Type.ERR_ADMONLY,
1956         520 : Type.ERR_OPERONLY,
1957         524 : Type.ERR_OPERSPVERIFY,
1958         610 : Type.RPL_MAPMORE,
1959         972 : Type.ERR_CANNOTDOCOMMAND,
1960         974 : Type.ERR_CANNOTCHANGECHANMODE,
1961     ];
1962 
1963     /++
1964         Delta typenum mappings for servers running the `ircu` (Undernet) daemon.
1965 
1966         - http://coder-com.undernet.org
1967      +/
1968     static immutable Type[569] ircu =
1969     [
1970         15 : Type.RPL_MAP,
1971         16 : Type.RPL_MAPMORE,
1972         17 : Type.RPL_MAPEND,
1973         222 : Type.RPL_STATSJLINE,
1974         228 : Type.RPL_STATSQLINE,
1975         238 : Type.RPL_STATSFLINE,
1976         246 : Type.RPL_STATSTLINE,
1977         247 : Type.RPL_STATSGLINE,
1978         248 : Type.RPL_STATSULINE,
1979         250 : Type.RPL_STATSCONN,
1980         270 : Type.RPL_PRIVS,
1981         275 : Type.RPL_STATSDLINE,
1982         276 : Type.RPL_STATSRLINE,
1983         281 : Type.RPL_ENDOFGLIST,
1984         282 : Type.RPL_JUPELIST,
1985         283 : Type.RPL_ENDOFJUPELIST,
1986         284 : Type.RPL_FEATURE,
1987         330 : Type.RPL_WHOISACCOUNT,
1988         334 : Type.RPL_LISTUSAGE,
1989         338 : Type.RPL_WHOISACTUALLY,
1990         391 : Type.RPL_TIME,
1991         437 : Type.ERR_BANNICKCHANGE,
1992         438 : Type.ERR_NICKTOOFAST,
1993         468 : Type.ERR_INVALIDUSERNAME,
1994         477 : Type.ERR_NEEDREGGEDNICK,
1995         493 : Type.ERR_NOFEATURE,
1996         494 : Type.ERR_BADFEATVALUE,
1997         495 : Type.ERR_BADLOGTYPE,
1998         512 : Type.ERR_NOSUCHGLINE,
1999         514 : Type.ERR_INVALID_ERROR,
2000         518 : Type.ERR_LONGMASK,
2001         519 : Type.ERR_TOOMANYUSERS,
2002         520 : Type.ERR_MASKTOOWIDE,
2003         524 : Type.ERR_QUARANTINED,
2004         568 : Type.ERR_LASTERROR,
2005     ];
2006 
2007     /++
2008         Delta typenum mappings for servers running the `aircd` (?) daemon.
2009 
2010         "After AnotherNet had become a commercial and proprietary-client chat
2011         network, the former users of AnotherNet's #trax decided to found their
2012         own network - "where free speech and ideas would be able to run
2013         unbounded through the pastures of #trax and #coders". They use the
2014         "`aircd`" IRC daemon, coded by an ex-member of the demoscene, simon
2015         kirby."
2016      +/
2017     static immutable Type[471] aircd =
2018     [
2019         210 : Type.RPL_STATS,
2020         274 : Type.RPL_ENDNOTIFY,
2021         285 : Type.RPL_CHANINFO_HANDLE,
2022         286 : Type.RPL_CHANINFO_USERS,
2023         287 : Type.RPL_CHANINFO_CHOPS,
2024         288 : Type.RPL_CHANINFO_VOICES,
2025         289 : Type.RPL_CHANINFO_AWAY,
2026         290 : Type.RPL_CHANINFO_OPERS,
2027         291 : Type.RPL_CHANINFO_BANNED,
2028         292 : Type.RPL_CHANINFO_BANS,
2029         293 : Type.RPL_CHANINFO_INVITE,
2030         294 : Type.RPL_CHANINFO_INVITES,
2031         295 : Type.RPL_CHANINFO_KICKS,
2032         308 : Type.RPL_NOTIFYACTION,
2033         309 : Type.RPL_NICKTRACE,
2034         377 : Type.RPL_KICKEXPIRED,
2035         378 : Type.RPL_BANEXPIRED,
2036         379 : Type.RPL_KICKLINKED,
2037         380 : Type.RPL_BANLINKED,
2038         470 : Type.ERR_KICKEDFROMCHAN,
2039     ];
2040 
2041     /++
2042         Delta typenum mappings for servers adhering to the `RFC1459` draft.
2043 
2044         - https://tools.ietf.org/html/rfc1459
2045      +/
2046     static immutable Type[502] rfc1459 =
2047     [
2048         214 : Type.RPL_STATSNLINE,
2049         217 : Type.RPL_STATSQLINE,
2050         232 : Type.RPL_ENDOFSERVICES,
2051         316 : Type.RPL_WHOISCHANOP, // deprecated
2052         391 : Type.RPL_TIME,
2053         492 : Type.ERR_NOSERVICEHOST,
2054         501 : Type.ERR_UMODEUNKNOWNFLAG,
2055     ];
2056 
2057     /++
2058         Delta typenum mappings for servers adhering to the `RFC2812` draft.
2059 
2060         - https://tools.ietf.org/html/rfc2812
2061      +/
2062     static immutable Type[485] rfc2812 =
2063     [
2064         240 : Type.RPL_STATSVLINE,
2065         246 : Type.RPL_STATSPING,
2066         247 : Type.RPL_STATSBLINE,
2067         250 : Type.RPL_STATSDLINE,
2068         262 : Type.RPL_TRACEEND,
2069         325 : Type.RPL_UNIQOPIS,
2070         437 : Type.ERR_UNAVAILRESOURCE,
2071         477 : Type.ERR_NOCHANMODES,
2072         484 : Type.ERR_RESTRICTED,
2073     ];
2074 
2075     /++
2076         Delta typenum mappings for servers running the `IRCD-Hybrid` daemon.
2077 
2078         - http://www.ircd-hybrid.org
2079      +/
2080     static immutable Type[716] hybrid =
2081     [
2082         220 : Type.RPL_STATSPLINE,
2083         224 : Type.RPL_STATSFLINE,
2084         225 : Type.RPL_STATSDLINE,
2085         226 : Type.RPL_STATSALINE,
2086         245 : Type.RPL_STATSSLINE,      // CONFLICT: Type.RPL_STATSTLINE
2087         246 : Type.RPL_STATSSERVICE,    // CONFLICT: Type.RPL_STATSULINE
2088         247 : Type.RPL_STATSXLINE,
2089         249 : Type.RPL_STATSDEBUG,
2090         276 : Type.RPL_WHOISCERTFP,     // oftc-hybrid?
2091         335 : Type.RPL_WHOISTEXT,
2092         336 : Type.RPL_INVITELIST,
2093         337 : Type.RPL_ENDOFINVITELIST, // CONFLICT: Type.RPL_WHOISTEXT
2094         344 : Type.RPL_QUIETLIST,       // oftc
2095         345 : Type.RPL_ENDOFQUIETLIST,  // CONFLICT: Type.RPL_INVITED, oftc
2096         386 : Type.RPL_RSACHALLENGE,
2097         396 : Type.RPL_VISIBLEHOST,
2098         408 : Type.ERR_NOCTRLSONCHAN,
2099         479 : Type.ERR_BADCHANNAME,
2100         480 : Type.ERR_SSLONLYCHAN,     // deprecated
2101         484 : Type.ERR_DESYNC,
2102         485 : Type.ERR_CHANBANREASON,
2103         492 : Type.ERR_NOCTCP,
2104         503 : Type.ERR_GHOSTEDCLIENT,
2105         524 : Type.ERR_HELPNOTFOUND,
2106         715 : Type.ERR_TOOMANYINVITE,
2107     ];
2108 
2109     /++
2110         Delta typenum mappings for servers running the `Solanum` daemon.
2111 
2112         - https://github.com/solanum-ircd/solanum
2113      +/
2114     static immutable Type[250] solanum =
2115     [
2116         249 : Type.RPL_STATSPLINE,
2117     ];
2118 
2119     /++
2120         Delta typenum mappings for servers running the `Bahamut` daemon
2121         (DALnet).
2122 
2123         - https://www.dal.net/?page=bahamut
2124      +/
2125     static immutable Type[621] bahamut =
2126     [
2127         220 : Type.RPL_STATSBLINE,
2128         222 : Type.RPL_STATSBLINE,
2129         223 : Type.RPL_STATSELINE,
2130         224 : Type.RPL_STATSFLINE,
2131         225 : Type.RPL_STATSCLONE,      // DEPRECATED CONFLICT: Type.RPL_STATSZLINE
2132         226 : Type.RPL_STATSCOUNT,
2133         227 : Type.RPL_STATSGLINE,
2134         245 : Type.RPL_STATSSLINE,
2135         275 : Type.RPL_USINGSSL,
2136         307 : Type.RPL_WHOISREGNICK,
2137         308 : Type.RPL_WHOISADMIN,
2138         309 : Type.RPL_WHOISADMIN,      // duplicate?
2139         310 : Type.RPL_WHOISSVCMSG,
2140         334 : Type.RPL_COMMANDSYNTAX,
2141         338 : Type.RPL_WHOISACTUALLY,
2142         408 : Type.ERR_NOCOLORSONCHAN,
2143         435 : Type.ERR_BANONCHAN,
2144         468 : Type.ERR_ONLYSERVERSCANCHANGE,
2145         477 : Type.ERR_NEEDREGGEDNICK,
2146         484 : Type.ERR_DESYNC,
2147         487 : Type.ERR_MSGSERVICES,
2148         488 : Type.ERR_NOSSL,
2149         493 : Type.ERR_NOSHAREDCHAN,
2150         494 : Type.ERR_OWNMODE,
2151         512 : Type.ERR_TOOMANYWATCH,
2152         514 : Type.ERR_TOOMANYDCC,
2153         521 : Type.ERR_LISTSYNTAX,
2154         617 : Type.RPL_DCCSTATUS,
2155         619 : Type.RPL_ENDOFDCCLIST,
2156         620 : Type.RPL_DCCINFO,
2157     ];
2158 
2159     /++
2160         Delta typenum mappings for servers running the `snircd` daemon
2161         (QuakeNet), based on `ircu`.
2162 
2163         - https://development.quakenet.org
2164      +/
2165     static immutable Type[554] snircd =
2166     [
2167         285 : Type.RPL_NEWHOSTIS,
2168         286 : Type.RPL_CHKHEAD,
2169         287 : Type.RPL_CHANUSER,
2170         288 : Type.RPL_PATCHHEAD,
2171         289 : Type.RPL_PATCHCON,
2172         290 : Type.RPL_DATASTR,
2173         291 : Type.RPL_ENDOFCHECK,
2174         485 : Type.ERR_ISREALSERVICE,
2175         486 : Type.ERR_ACCOUNTONLY,
2176         553 : Type.ERR_STATSSLINE,
2177     ];
2178 
2179     /++
2180         Delta typenum mappings for servers running the `Nefarious` or
2181         `Nefarious2` daemons, based on `ircu`.
2182 
2183         - https://github.com/evilnet/nefarious
2184         - https://github.com/evilnet/nefarious2
2185      +/
2186     static immutable Type[976] nefarious =
2187     [
2188         220 : Type.RPL_STATSWLINE,
2189         292 : Type.ERR_SEARCHNOMATCH,
2190         316 : Type.RPL_WHOISPRIVDEAF,
2191         320 : Type.RPL_WHOISWEBIRC,
2192         335 : Type.RPL_WHOISACCOUNTONLY,
2193         336 : Type.RPL_WHOISBOT,
2194         339 : Type.RPL_WHOISMARKS,
2195         386 : Type.RPL_IRCOPSHEADER,
2196         387 : Type.RPL_IRCOPS,
2197         388 : Type.RPL_ENDOFIRCOPS,
2198         521 : Type.ERR_NOSUCHGLINE,
2199         568 : Type.RPL_NOMOTD,
2200         617 : Type.RPL_WHOISSSLFP,
2201         975 : Type.ERR_LASTERROR,
2202     ];
2203 
2204     /++
2205         Delta typenum mappings for `RusNet` servers. Unsure of what daemon they
2206         run.
2207 
2208         - http://www.rus-net.org
2209      +/
2210     static immutable Type[501] rusnet =
2211     [
2212         222 : Type.RPL_CODEPAGE,
2213         223 : Type.RPL_CHARSET,
2214         327 : Type.RPL_WHOISHOST,
2215         468 : Type.ERR_NOCODEPAGE,
2216         470 : Type.ERR_7BIT,
2217         479 : Type.ERR_NOCOLOR,
2218         480 : Type.ERR_NOWALLOP,
2219         486 : Type.ERR_RLINED,
2220         500 : Type.ERR_NOREHASHPARAM,
2221     ];
2222 
2223     /++
2224         Delta typenum mappings for `Rizon` network servers. Supposedly they use
2225         a mixture of Hybrid typenums, plus a few of their own.
2226 
2227         - https://www.rizon.net
2228      +/
2229     static immutable Type[716] rizon =
2230     [
2231         227 : Type.RPL_STATSBLINE,
2232         672 : Type.RPL_WHOISREALIP,
2233         715 : Type.RPL_INVITETHROTTLE,
2234     ];
2235 
2236     /++
2237         Delta typenum mappings for `austHex` AUSTNet Development servers.
2238 
2239         - https://sourceforge.net/projects/austhex
2240      +/
2241     static immutable Type[521] austHex =
2242     [
2243         240 : Type.RPL_STATSXLINE,
2244         307 : Type.RPL_SUSERHOST,
2245         309 : Type.RPL_WHOISHELPER,
2246         310 : Type.RPL_WHOISSERVICE,
2247         320 : Type.RPL_WHOISVIRT,
2248         357 : Type.RPL_MAP,
2249         358 : Type.RPL_MAPMORE,
2250         359 : Type.RPL_MAPEND,
2251         377 : Type.RPL_SPAM,            // deprecated
2252         378 : Type.RPL_MOTD,
2253         380 : Type.RPL_YOURHELPER,
2254         434 : Type.ERR_SERVICENAMEINUSE,
2255         480 : Type.ERR_NOULINE,
2256         503 : Type.ERR_VWORLDWARN,
2257         520 : Type.ERR_WHOTRUNC,        // deprecated
2258     ];
2259 
2260     /++
2261         Delta typenum mappings for the `IRCnet` network of servers. Unsure of
2262         what server daemon they run.
2263 
2264         - http://www.ircnet.org
2265      +/
2266     static immutable Type[489] ircNet =
2267     [
2268         245 : Type.RPL_STATSSLINE,
2269         248 : Type.RPL_STATSDEFINE,
2270         274 : Type.RPL_STATSDELTA,
2271         344 : Type.RPL_REOPLIST,
2272         345 : Type.RPL_ENDOFREOPLIST,
2273         438 : Type.ERR_DEAD,
2274         487 : Type.ERR_CHANTOORECENT,
2275         488 : Type.ERR_TSLESSCHAN,
2276     ];
2277 
2278     /++
2279         Delta typenum mappings for servers running the `PTlink` daemon.
2280 
2281         - https://sourceforge.net/projects/ptlinksoft
2282      +/
2283     static immutable Type[616] ptlink =
2284     [
2285         247 : Type.RPL_STATSXLINE,
2286         484 : Type.ERR_DESYNC,
2287         485 : Type.ERR_CANTKICKADMIN,
2288         615 : Type.RPL_MAPMORE,
2289     ];
2290 
2291     /++
2292         Delta typenum mappings for servers running the `InspIRCd` daemon.
2293 
2294         - http://www.inspircd.org
2295      +/
2296     static immutable Type[976] inspIRCd =
2297     [
2298         270 : Type.RPL_MAPUSERS,
2299         304 : Type.RPL_SYNTAX,
2300         379 : Type.RPL_WHOWASIP,  // also encountered as Type.RPL_WHOISMODES?
2301         495 : Type.ERR_DELAYREJOIN,
2302         501 : Type.ERR_UNKNOWNSNOMASK,
2303         702 : Type.RPL_COMMANDS,
2304         703 : Type.RPL_COMMANDSEND,
2305         953 : Type.ENDOFEXEMPTOPSLIST,
2306         972 : Type.ERR_CANTUNLOADMODULE,
2307         974 : Type.ERR_CANTLOADMODULE,
2308         975 : Type.RPL_LOADEDMODULE
2309     ];
2310 
2311     /++
2312         Delta typenum mapping for servers running the `ultimate` daemon.
2313         Based off of `Bahamut`.
2314      +/
2315     static immutable Type[624] ultimate =
2316     [
2317         275 : Type.RPL_USINGSSL,
2318         386 : Type.RPL_IRCOPS,
2319         387 : Type.RPL_ENDOFIRCOPS,
2320         434 : Type.ERR_NORULES,
2321         610 : Type.RPL_ISOPER,
2322         615 : Type.RPL_WHOISMODES,
2323         616 : Type.RPL_WHOISHOST,
2324         617 : Type.RPL_WHOISBOT,
2325         619 : Type.RPL_WHOWASHOST,
2326         620 : Type.RPL_RULESSTART,
2327         621 : Type.RPL_RULES,
2328         622 : Type.RPL_ENDOFRULES,
2329         623 : Type.RPL_MAPMORE,
2330     ];
2331 
2332     /++
2333         Delta typenum mappings extending `ircu` typenums, for UnderNet.
2334 
2335         - https://github.com/UndernetIRC/ircu2
2336      +/
2337     static immutable Type[490] undernet =
2338     [
2339         396 : Type.RPL_HOSTHIDDEN,
2340         484 : Type.ERR_ISCHANSERVICE,
2341         489 : Type.ERR_VOICENEEDED,
2342     ];
2343 
2344     /++
2345         Delta typenum mapping for servers running the `ratbox` daemon. It is
2346         primarily used on EFnet.
2347 
2348         - https://www.ratbox.org
2349      +/
2350     static immutable Type[716] ratBox =
2351     [
2352         480 : Type.ERR_THROTTLE,
2353         485 : Type.ERR_BANNEDNICK,      // deprecated
2354         702 : Type.RPL_MODLIST,
2355         703 : Type.RPL_ENDOFMODLIST,
2356         715 : Type.ERR_KNOCKDISABLED,
2357     ];
2358 
2359     /++
2360         Delta typenum mappings for servers running the `charybdis` daemon.
2361 
2362         - https://github.com/charybdis-ircd/charybdis
2363      +/
2364     static immutable Type[495] charybdis =
2365     [
2366         492 : Type.ERR_CANNOTSENDTOUSER,
2367         494 : Type.ERR_OWNMODE,
2368     ];
2369 
2370     /++
2371         Delta typenum mappings for servers running the `sorircd` daemon
2372         (SorceryNet).
2373 
2374         - http://www.nongnu.org/snservices/sorircd.html
2375      +/
2376     static immutable Type[326] sorircd =
2377     [
2378         325 : Type.RPL_CHANNELMLOCKIS,  // deprecated
2379     ];
2380 
2381     /*
2382     static immutable Type[321] anothernet =
2383     [
2384         320 : Type.RPL_WHOIS_HIDDEN,
2385     ];
2386 
2387     static immutable Type[392] bdqIRCd =
2388     [
2389         391 : Type.RPL_TIME,
2390     ];
2391 
2392     static immutable Type[488] chatIRCd =
2393     [
2394         487 : Type.ERR_NONONSSL,
2395     ];
2396 
2397     static immutable Type[515] irch =
2398     [
2399         514 : Type.ERR_NOSUCHJUPE,
2400     ];
2401 
2402     static immutable Type[672] ithildin =
2403     [
2404         672 : Type.RPL_UNKNOWNMODES,
2405     ];
2406     */
2407 }
2408 
2409 
2410 // IRCChannel
2411 /++
2412     Aggregate personifying an IRC channel and its state.
2413 
2414     An IRC channel may have a topic, a creation date, and one or more *modes*.
2415     Modes define how the channel behaves and how it treats its users, including
2416     which ones have operator and voice status, as well as which are banned, and more.
2417  +/
2418 struct IRCChannel
2419 {
2420     /++
2421         A channel mode.
2422 
2423         Some modes overwrite themselves; a channel may be `+i` or `-i`, never
2424         `i` twice. Others stack; a channel may have an arbitrary number of `b`
2425         bans. We try our best to support both.
2426      +/
2427     static struct Mode
2428     {
2429         /++
2430             The character that implies this [Mode] (`i`, `z`, `l` ...).
2431          +/
2432         char modechar;
2433 
2434         /++
2435             The data associated with the [Mode], if applicable. This is often a
2436             number, such as what `l` takes (join limit).
2437          +/
2438         string data;
2439 
2440         /++
2441             The user associated with the [Mode], when it is not just [Mode.data|data].
2442          +/
2443         IRCUser user;
2444 
2445         /++
2446             The channel this mode refers to, where applicable.
2447          +/
2448         string channel;
2449 
2450         /++
2451             Users that are explicitly exempt from the [Mode].
2452          +/
2453         IRCUser[] exceptions;
2454 
2455         /++
2456             Whether or not this [Mode] should be considered to be its own antithesis.
2457          +/
2458         bool negated;
2459 
2460         /++
2461             Compare two [Mode]s with each other to see if they are both of the
2462             same type, as well as having the same [data] and/or [user].
2463 
2464             Params:
2465                 that = Other [Mode] to compare this one with.
2466 
2467             Returns:
2468                 `true` if the [Mode]s match, `false` if not.
2469          +/
2470         auto opEquals(const Mode that) const pure @safe nothrow @nogc
2471         {
2472             // Ignore exemptions when comparing Modes
2473             immutable charMatch = (this.modechar == that.modechar);
2474             immutable dataMatch = (this.data == that.data);
2475             immutable userMatch = (this.user == that.user);  // IRCUser.opEquals
2476             immutable chanMatch = (this.channel == that.channel);
2477 
2478             immutable match = (charMatch && dataMatch && userMatch && chanMatch);
2479             return negated ? !match : match;
2480         }
2481 
2482         /++
2483             Produces a hash for this [Mode].
2484 
2485             Returns:
2486                 A hash.
2487          +/
2488         auto toHash() const pure @safe
2489         {
2490             import std.conv : text;
2491             return text(modechar, data, user.hashOf, channel, negated).hashOf;
2492         }
2493     }
2494 
2495     /++
2496         The channel name.
2497      +/
2498     string name;
2499 
2500     /++
2501         The current topic of the channel, as set by operators.
2502      +/
2503     string topic;
2504 
2505     /++
2506         The current non-[data]-sporting [Mode]s of the channel.
2507      +/
2508     string modechars;
2509 
2510     /++
2511         Array of all [Mode]s that are not simply represented in [modechars].
2512      +/
2513     Mode[] modes;
2514 
2515     /++
2516         Associative array of all the nicknames inhabiting the channel.
2517      +/
2518     bool[string] users;
2519 
2520     /++
2521         Associative array of nicknames with a prefixing channel mode (operator,
2522         halfops, voiced, ...) keyed by modechar.
2523      +/
2524     bool[string][char] mods;
2525 
2526     /++
2527         Template to deduplicate code for mods shorthands.
2528 
2529         Params:
2530             prefix = Mode character.
2531 
2532         Returns:
2533             A `bool[string]` hashmap of all users with the given mode character
2534             as keys.
2535      +/
2536     ref bool[string] modsShorthand(char prefix)()
2537     {
2538         auto modsOp = prefix in mods;
2539 
2540         if (!modsOp)
2541         {
2542             this.mods[prefix][string.init] = false;
2543             modsOp = prefix in this.mods;
2544             (*modsOp).remove(string.init);
2545         }
2546 
2547         return *modsOp;
2548     }
2549 
2550     /++
2551         Array of channel operators.
2552      +/
2553     alias ops = modsShorthand!'o';
2554 
2555     /++
2556         Array of channel halfops.
2557      +/
2558     alias halfops = modsShorthand!'h';
2559 
2560     /++
2561         Array of voiced channel users.
2562      +/
2563     alias voiced = modsShorthand!'v';
2564 
2565     /++
2566         When the channel was created, expressed in UNIX time.
2567      +/
2568     long created;
2569 }
2570 
2571 
2572 // IRCClient
2573 /++
2574     Aggregate collecting all the relevant settings, options and state needed for
2575     a connection to an IRC server.
2576 
2577     Many fields are transient and unfit to be saved to disk.
2578  +/
2579 struct IRCClient
2580 {
2581     /++
2582         Client nickname.
2583      +/
2584     string nickname; // = "kameloso";
2585 
2586     /++
2587         Client "user".
2588      +/
2589     string user; // = "kameloso";
2590 
2591     /++
2592         Client GECOS/"real name".
2593      +/
2594     string realName; // = "kameloso IRC bot";
2595 
2596     @Unserialisable
2597     {
2598         /++
2599             The original client nickname before connecting, in case it changed.
2600          +/
2601         string origNickname;
2602 
2603         /++
2604             Client IDENT identifier. Defaults to "~`user`".
2605             Unused but keep for future expansion.
2606          +/
2607         string ident;
2608 
2609         version(TwitchSupport)
2610         {
2611             /++
2612                 Our Twitch display name or alias.
2613              +/
2614             string displayName;
2615         }
2616 
2617         /++
2618             The current modechars active on the client (e.g. "ix");
2619          +/
2620         string modes;
2621     }
2622 }