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         With a numeric event, the number of the event type.
872      +/
873     uint num;
874 
875     /++
876         The raw IRC string, untouched.
877      +/
878     @Hidden string raw;
879 
880     /++
881         The name of whoever (or whatever) sent this event.
882      +/
883     IRCUser sender;
884 
885     /++
886         The channel the event transpired in, or is otherwise related to.
887      +/
888     string channel;
889 
890     /++
891         The target user of the event.
892      +/
893     IRCUser target;
894 
895     /++
896         The main body of text of the event.
897      +/
898     string content;
899 
900     /++
901         Auxiliary string array.
902      +/
903     string[numAuxStrings] aux;
904 
905     /++
906         IRCv3 message tags attached to this event
907      +/
908     string tags;
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             Contents of the [IRCEvent.Type.RPL_ISUPPORT|RPL_ISUPPORT] response(s).
1092          +/
1093         string supports;
1094 
1095         /++
1096             `EXTBAN` types.
1097          +/
1098         string extbanTypes;
1099 
1100         /++
1101             The current case mapping, dictating how case-insensitivity works.
1102          +/
1103         CaseMapping caseMapping;
1104 
1105         /++
1106             `EXTBAN` prefix character.
1107          +/
1108         char extbanPrefix = '$';
1109 
1110         /++
1111             The modechar for mode exceptions.
1112          +/
1113         char exceptsChar = 'e';
1114 
1115         /++
1116             The modechar for invite exceptions.
1117          +/
1118         char invexChar = 'I';
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     version(TwitchSupport)
1173     {
1174         /++
1175             The Twitch ID of this user's account.
1176          +/
1177         uint id;
1178     }
1179 
1180     /++
1181         The user's GECOS/"real name".
1182      +/
1183     string realName;
1184 
1185     /++
1186         The user's IDENT identification.
1187      +/
1188     string ident;
1189 
1190     /++
1191         The reported user address, which may be a cloak.
1192      +/
1193     string address;
1194 
1195     /++
1196         Services account name (to `NickServ`, `AuthServ`, `Q`, etc).
1197      +/
1198     string account;
1199 
1200     /++
1201         Timestamp when the user was last modified.
1202      +/
1203     @Hidden long updated;
1204 
1205     version(TwitchSupport)
1206     {
1207         // Twitch has some extra features.
1208 
1209         /++
1210             The alternate "display name" of the user.
1211          +/
1212         string displayName;
1213 
1214         /++
1215             The Twitch badges this user has.
1216          +/
1217         string badges;
1218 
1219         /++
1220             The Twitch colour (RRGGBB) to tint the user's nickname with.
1221          +/
1222         string colour;
1223     }
1224 
1225     /++
1226         Create a new [IRCUser] based on a `*!*@*` mask string.
1227      +/
1228     this(string userstring) pure @safe
1229     {
1230         import std.format : formattedRead;
1231 
1232         userstring.formattedRead("%s!%s@%s", nickname, ident, address);
1233         if (nickname == "*") nickname = string.init;
1234         if (ident == "*") ident = string.init;
1235         if (address == "*") address = string.init;
1236     }
1237 
1238     ///
1239     unittest
1240     {
1241         {
1242             immutable user = IRCUser("nickname!~ident@address");
1243             assert((user.nickname == "nickname"), user.nickname);
1244             assert((user.ident == "~ident"), user.ident);
1245             assert((user.address == "address"), user.address);
1246         }
1247         {
1248             immutable user = IRCUser("*!~ident@address");
1249             assert(!user.nickname.length, user.nickname);
1250             assert((user.ident == "~ident"), user.ident);
1251             assert((user.address == "address"), user.address);
1252         }
1253         {
1254             immutable user = IRCUser("*!*@*");
1255             assert(!user.nickname.length, user.nickname);
1256             assert(!user.ident.length, user.ident);
1257             assert(!user.address.length, user.address);
1258         }
1259     }
1260 
1261     /++
1262         Create a new [IRCUser] inheriting passed `nickname`, `ident`, and
1263         `address` strings.
1264      +/
1265     auto this(
1266         const string nickname,
1267         const string ident,
1268         const string address) pure @safe nothrow @nogc
1269     {
1270         this.nickname = nickname;
1271         this.ident = ident;
1272         this.address = address;
1273     }
1274 
1275     /++
1276         Makes an educated guess that a sender is a server.
1277 
1278         Returns:
1279             `true` if the sender nickname and/or address looks to be a server's,
1280             `false` if not.
1281      +/
1282     auto isServer() const @property pure @safe nothrow @nogc
1283     {
1284         import std.string : indexOf;
1285         return !nickname.length && (address.indexOf('.') != -1);
1286     }
1287 
1288     ///
1289     @safe unittest
1290     {
1291         IRCUser user;
1292 
1293         user.address = "blah.freenode.net";
1294         assert(user.isServer);
1295 
1296         user.nickname = "foo";
1297         assert(!user.isServer);
1298 
1299         user.nickname = string.init;
1300         user.address = "nodots";
1301         assert(!user.isServer);  // unsure what to even make of no-dot addresses
1302 
1303         // :kameloso MODE kameloso :+i
1304         user.nickname = "kameloso";
1305         user.address = string.init;
1306         assert(!user.isServer);
1307     }
1308 
1309     /++
1310         Compares two [IRCUser]s with each other, ignoring members considered to
1311         be extra or optional.
1312 
1313         Params:
1314             that = Second user to compare this one with.
1315 
1316         Returns:
1317             `true` if the users match, `false` if not.
1318      +/
1319     auto opEquals(const IRCUser that) const pure @safe nothrow @nogc
1320     {
1321         return
1322             (this.nickname == that.nickname) &&
1323             (this.ident == that.ident) &&
1324             (this.address == that.address);
1325     }
1326 
1327     /++
1328         Produces a hash for this [IRCUser].
1329 
1330         Returns:
1331             A hash.
1332      +/
1333     auto toHash() const pure @safe
1334     {
1335         return this.hostmask.hashOf;
1336     }
1337 
1338     // toString
1339     /++
1340         Formats this [IRCUser] into a hostmask representing its values.
1341         Stores the result in the passed output range sink.
1342 
1343         Params:
1344             sink = Output range sink to save the hostmask string to.
1345      +/
1346     void toString(Sink)(auto ref Sink sink) const @safe
1347     {
1348         import std.format : formattedWrite;
1349 
1350         immutable nickname = this.nickname.length ? this.nickname : "*";
1351         immutable ident = this.ident.length ? this.ident : "*";
1352         immutable address = this.address.length ? this.address : "*";
1353 
1354         sink.formattedWrite("%s!%s@%s", nickname, ident, address);
1355     }
1356 
1357     // hostmask
1358     /++
1359         Formats this [IRCUser] into a hostmask representing its values.
1360         Merely wraps [toString] and returns a newly allocated string.
1361 
1362         Returns:
1363             A hostmask "*!*@*" string.
1364      +/
1365     string hostmask() pure @safe const
1366     {
1367         import std.array : Appender;
1368 
1369         Appender!(char[]) sink;
1370         sink.reserve(nickname.length + ident.length + address.length + 5);  // for ! and @ as well as ***
1371 
1372         this.toString(sink);
1373         return sink.data;
1374     }
1375 
1376     ///
1377     @safe unittest
1378     {
1379         {
1380             const user = IRCUser("nickname", "ident", "address.tld");
1381             immutable hostmask = user.hostmask;
1382             assert((hostmask == "nickname!ident@address.tld"), hostmask);
1383         }
1384         {
1385             const user = IRCUser("nickname", string.init, "address.tld");
1386             immutable hostmask = user.hostmask;
1387             assert((hostmask == "nickname!*@address.tld"), hostmask);
1388         }
1389         {
1390             const user = IRCUser(string.init, string.init, "address.tld");
1391             immutable hostmask = user.hostmask;
1392             assert((hostmask == "*!*@address.tld"), hostmask);
1393         }
1394         {
1395             const IRCUser user;
1396             immutable hostmask = user.hostmask;
1397             assert((hostmask == "*!*@*"), hostmask);
1398         }
1399     }
1400 }
1401 
1402 
1403 // Typenums
1404 /++
1405     Reverse mappings of *numerics* to [IRCEvent.Type|Type]s.
1406 
1407     One `base` table that covers most cases, and then specialised arrays for
1408     different server daemons, to meld into `base` for a union of the two
1409     (or more). This speeds up translation greatly and allows us to have
1410     different mappings for different daemons.
1411  +/
1412 struct Typenums
1413 {
1414 private:
1415     alias Type = IRCEvent.Type;
1416 
1417 public:
1418     /++
1419         Default mappings.
1420      +/
1421     static immutable Type[1024] base =
1422     [
1423         1   : Type.RPL_WELCOME,
1424         2   : Type.RPL_YOURHOST,
1425         3   : Type.RPL_CREATED,
1426         4   : Type.RPL_MYINFO,
1427         5   : Type.RPL_ISUPPORT,
1428         6   : Type.RPL_MAP,
1429         7   : Type.RPL_MAPEND,
1430         8   : Type.RPL_SNOMASK,
1431         9   : Type.RPL_STATMEMTOT,
1432         10  : Type.THISSERVERINSTEAD,  // was Type.RPL_STATMEM
1433         14  : Type.RPL_YOURCOOKIE,
1434         15  : Type.RPL_MAP,
1435         16  : Type.RPL_MAPMORE,
1436         17  : Type.RPL_MAPEND,
1437         20  : Type.RPL_HELLO,
1438         30  : Type.RPL_APASSWARN_SET,
1439         31  : Type.RPL_APASSWARN_SECRET,
1440         32  : Type.RPL_APASSWARN_CLEAR,
1441         42  : Type.RPL_YOURID,
1442         43  : Type.RPL_SAVENICK,
1443         50  : Type.RPL_ATTEMPTINGJUNC,
1444         51  : Type.RPL_ATTEMPTINGREROUTE,
1445         105 : Type.RPL_REMOTEISUPPORT,
1446         200 : Type.RPL_TRACELINK,
1447         201 : Type.RPL_TRACECONNECTING,
1448         202 : Type.RPL_TRACEHANDSHAKE,
1449         203 : Type.RPL_TRACEUNKNOWN,
1450         204 : Type.RPL_TRACEOPERATOR,
1451         205 : Type.RPL_TRACEUSER,
1452         206 : Type.RPL_TRACESERVER,
1453         207 : Type.RPL_TRACESERVICE,
1454         208 : Type.RPL_TRACENEWTYPE,
1455         209 : Type.RPL_TRACECLASS,
1456         210 : Type.RPL_STATS,
1457         211 : Type.RPL_STATSLINKINFO,
1458         212 : Type.RPL_STATSCOMMAND,
1459         213 : Type.RPL_STATSCLINE,
1460         214 : Type.RPL_STATSNLINE,
1461         215 : Type.RPL_STATSILINE,
1462         216 : Type.RPL_STATSKLINE,
1463         217 : Type.RPL_STATSQLINE,
1464         218 : Type.RPL_STATSYLINE,
1465         219 : Type.RPL_ENDOFSTATS,
1466         220 : Type.RPL_STATSPLINE,
1467         221 : Type.RPL_UMODEIS,
1468         222 : Type.RPL_MODLIST,
1469         223 : Type.RPL_STATSELINE,
1470         224 : Type.RPL_STATSFLINE,
1471         225 : Type.RPL_STATSDLINE,
1472         226 : Type.RPL_STATSCOUNT,
1473         227 : Type.RPL_STATSBLINE,
1474         228 : Type.RPL_STATSQLINE,
1475         229 : Type.RPL_STATSSPAMF,
1476         230 : Type.RPL_STATSEXCEPTTKL,
1477         231 : Type.RPL_SERVICEINFO,
1478         232 : Type.RPL_ENDOFSERVICES,
1479         233 : Type.RPL_SERVICE,
1480         234 : Type.RPL_SERVLIST,
1481         235 : Type.RPL_SERVLISTEND,
1482         236 : Type.RPL_STATSVERBOSE,
1483         237 : Type.RPL_STATSENGINE,
1484         238 : Type.RPL_STATSFLINE,
1485         239 : Type.RPL_STATSIAUTH,
1486         240 : Type.RPL_STATSVLINE,
1487         241 : Type.RPL_STATSLLINE,
1488         242 : Type.RPL_STATSUPTIME,
1489         243 : Type.RPL_STATSOLINE,
1490         244 : Type.RPL_STATSHLINE,
1491         245 : Type.RPL_STATSSLINE,
1492         246 : Type.RPL_STATSPING,
1493         247 : Type.RPL_STATSBLINE,
1494         248 : Type.RPL_STATSULINE,
1495         249 : Type.RPL_STATSULINE,
1496         250 : Type.RPL_STATSCONN,
1497         251 : Type.RPL_LUSERCLIENT,
1498         252 : Type.RPL_LUSEROP,
1499         253 : Type.RPL_LUSERUNKNOWN,
1500         254 : Type.RPL_LUSERCHANNELS,
1501         255 : Type.RPL_LUSERME,
1502         256 : Type.RPL_ADMINME,
1503         257 : Type.RPL_ADMINLOC1,
1504         258 : Type.RPL_ADMINLOC2,
1505         259 : Type.RPL_ADMINEMAIL,
1506         261 : Type.RPL_TRACELOG,
1507         262 : Type.RPL_TRACEEND,
1508         263 : Type.RPL_TRYAGAIN,
1509         264 : Type.RPL_USINGSSL,
1510         265 : Type.RPL_LOCALUSERS,
1511         266 : Type.RPL_GLOBALUSERS,
1512         267 : Type.RPL_START_NETSTAT,
1513         268 : Type.RPL_NETSTAT,
1514         269 : Type.RPL_END_NETSTAT,
1515         270 : Type.RPL_PRIVS,
1516         271 : Type.RPL_SILELIST,
1517         272 : Type.RPL_ENDOFSILELIST,
1518         273 : Type.RPL_NOTIFY,
1519         274 : Type.RPL_ENDNOTIFY,
1520         275 : Type.RPL_STATSDLINE,
1521         276 : Type.RPL_STATSRLINE,
1522         277 : Type.RPL_VCHANLIST,
1523         278 : Type.RPL_VCHANHELP,
1524         280 : Type.RPL_GLIST,
1525         281 : Type.RPL_ACCEPTLIST,
1526         282 : Type.RPL_ENDOFACCEPT,
1527         283 : Type.RPL_ALIST,
1528         284 : Type.RPL_ENDOFALIST,
1529         285 : Type.RPL_GLIST_HASH,
1530         286 : Type.RPL_CHANINFO_USERS,
1531         287 : Type.RPL_CHANINFO_CHOPS,
1532         288 : Type.RPL_CHANINFO_VOICES,
1533         289 : Type.RPL_CHANINFO_AWAY,
1534         290 : Type.RPL_CHANINFO_OPERS,
1535         291 : Type.RPL_CHANINFO_BANNED,
1536         292 : Type.RPL_CHANINFO_BANS,
1537         293 : Type.RPL_CHANINFO_INVITE,
1538         294 : Type.RPL_CHANINFO_INVITES,
1539         295 : Type.RPL_CHANINFO_KICK,
1540         296 : Type.RPL_CHANINFO_KICKS,
1541         299 : Type.RPL_END_CHANINFO,
1542         300 : Type.RPL_NONE,
1543         301 : Type.RPL_AWAY,
1544         302 : Type.RPL_USERHOST,
1545         303 : Type.RPL_ISON,
1546         304 : Type.RPL_TEXT,
1547         305 : Type.RPL_UNAWAY,
1548         306 : Type.RPL_NOWAWAY,
1549         307 : Type.RPL_WHOISREGNICK,
1550         308 : Type.RPL_NOTIFYACTION,
1551         309 : Type.RPL_NICKTRACE,
1552         310 : Type.RPL_WHOISSVCMSG,
1553         311 : Type.RPL_WHOISUSER,
1554         312 : Type.RPL_WHOISSERVER,
1555         313 : Type.RPL_WHOISOPERATOR,
1556         314 : Type.RPL_WHOWASUSER,
1557         315 : Type.RPL_ENDOFWHO,
1558         316 : Type.RPL_WHOISCHANOP,
1559         317 : Type.RPL_WHOISIDLE,
1560         318 : Type.RPL_ENDOFWHOIS,
1561         319 : Type.RPL_WHOISCHANNELS,
1562         320 : Type.RPL_WHOISSPECIAL,
1563         321 : Type.RPL_LISTSTART,
1564         322 : Type.RPL_LIST,
1565         323 : Type.RPL_LISTEND,
1566         324 : Type.RPL_CHANNELMODEIS,
1567         325 : Type.RPL_CHANNELPASSIS,
1568         326 : Type.RPL_NOCHANPASS,
1569         327 : Type.RPL_CHPASSUNKNOWN,
1570         328 : Type.RPL_CHANNEL_URL,
1571         329 : Type.RPL_CREATIONTIME,
1572         330 : Type.RPL_WHOISACCOUNT,
1573         331 : Type.RPL_NOTOPIC,
1574         332 : Type.RPL_TOPIC,
1575         333 : Type.RPL_TOPICWHOTIME,
1576         334 : Type.RPL_LISTUSAGE,
1577         335 : Type.RPL_WHOISBOT,
1578         336 : Type.RPL_INVITELIST,
1579         337 : Type.RPL_ENDOFINVITELIST,
1580         338 : Type.RPL_WHOISACTUALLY,
1581         339 : Type.RPL_BADCHANPASS,
1582         340 : Type.RPL_USERIP,
1583         341 : Type.RPL_INVITING,
1584         342 : Type.RPL_SUMMONING,
1585         343 : Type.RPL_WHOISKILL,
1586         345 : Type.RPL_INVITED,
1587         346 : Type.RPL_INVITELIST,
1588         347 : Type.RPL_ENDOFINVITELIST,
1589         348 : Type.RPL_EXCEPTLIST,
1590         349 : Type.RPL_ENDOFEXCEPTLIST,
1591         351 : Type.RPL_VERSION,
1592         352 : Type.RPL_WHOREPLY,
1593         353 : Type.RPL_NAMREPLY,
1594         354 : Type.RPL_WHOSPCRPL,
1595         355 : Type.RPL_NAMREPLY_,
1596         357 : Type.RPL_MAP,
1597         358 : Type.RPL_MAPMORE,
1598         359 : Type.RPL_MAPEND,
1599         360 : Type.RPL_WHOWASREAL,
1600         361 : Type.RPL_KILLDONE,
1601         362 : Type.RPL_CLOSING,
1602         363 : Type.RPL_CLOSEEND,
1603         364 : Type.RPL_LINKS,
1604         365 : Type.RPL_ENDOFLINKS,
1605         366 : Type.RPL_ENDOFNAMES,
1606         367 : Type.RPL_BANLIST,
1607         368 : Type.RPL_ENDOFBANLIST,
1608         369 : Type.RPL_ENDOFWHOWAS,
1609         371 : Type.RPL_INFO,
1610         372 : Type.RPL_MOTD,
1611         373 : Type.RPL_INFOSTART,
1612         374 : Type.RPL_ENDOFINFO,
1613         375 : Type.RPL_MOTDSTART,
1614         376 : Type.RPL_ENDOFMOTD,
1615         377 : Type.RPL_KICKEXPIRED,
1616         378 : Type.RPL_WHOISHOST,
1617         379 : Type.RPL_WHOISMODES,
1618         380 : Type.RPL_BANLINKED,
1619         381 : Type.RPL_YOUREOPER,
1620         382 : Type.RPL_REHASHING,
1621         383 : Type.RPL_YOURESERVICE,
1622         384 : Type.RPL_MYPORTIS,
1623         385 : Type.RPL_NOTOPERANYMORE,
1624         386 : Type.RPL_QLIST,
1625         387 : Type.RPL_ENDOFQLIST,
1626         388 : Type.RPL_ALIST,
1627         389 : Type.RPL_ENDOFALIST,
1628         391 : Type.RPL_TIME,
1629         392 : Type.RPL_USERSTART,
1630         393 : Type.RPL_USERS,
1631         394 : Type.RPL_ENDOFUSERS,
1632         395 : Type.RPL_NOUSERS,
1633         396 : Type.RPL_HOSTHIDDEN,
1634         400 : Type.ERR_UNKNOWNERROR,
1635         401 : Type.ERR_NOSUCHNICK,
1636         402 : Type.ERR_NOSUCHSERVER,
1637         403 : Type.ERR_NOSUCHCHANNEL,
1638         404 : Type.ERR_CANNOTSENDTOCHAN,
1639         405 : Type.ERR_TOOMANYCHANNELS,
1640         406 : Type.ERR_WASNOSUCHNICK,
1641         407 : Type.ERR_TOOMANYTARGETS,
1642         408 : Type.ERR_NOSUCHSERVICE,
1643         409 : Type.ERR_NOORIGIN,
1644         410 : Type.ERR_INVALIDCAPCMD,
1645         411 : Type.ERR_NORECIPIENT,
1646         412 : Type.ERR_NOTEXTTOSEND,
1647         413 : Type.ERR_NOTOPLEVEL,
1648         414 : Type.ERR_WILDTOPLEVEL,
1649         415 : Type.ERR_BADMASK,
1650         416 : Type.ERR_TOOMANYMATCHES,
1651         417 : Type.ERR_INPUTTOOLONG,
1652         419 : Type.ERR_LENGTHTRUNCATED,
1653         421 : Type.ERR_UNKNOWNCOMMAND,
1654         422 : Type.ERR_NOMOTD,
1655         423 : Type.ERR_NOADMININFO,
1656         424 : Type.ERR_FILEERROR,
1657         425 : Type.ERR_NOOPERMOTD,
1658         429 : Type.ERR_TOOMANYAWAY,
1659         430 : Type.ERR_EVENTNICKCHANGE,
1660         431 : Type.ERR_NONICKNAMEGIVEN,
1661         432 : Type.ERR_ERRONEOUSNICKNAME,
1662         433 : Type.ERR_NICKNAMEINUSE,
1663         434 : Type.ERR_NORULES,
1664         435 : Type.ERR_BANONCHAN,
1665         436 : Type.ERR_NICKCOLLISION,
1666         437 : Type.ERR_UNAVAILRESOURCE,
1667         438 : Type.ERR_NICKTOOFAST,
1668         439 : Type.ERR_TARGETTOOFAST,
1669         440 : Type.ERR_SERVICESDOWN,
1670         441 : Type.ERR_USERNOTINCHANNEL,
1671         442 : Type.ERR_NOTONCHANNEL,
1672         443 : Type.ERR_USERONCHANNEL,
1673         444 : Type.ERR_NOLOGIN,
1674         445 : Type.ERR_SUMMONDISABLED,
1675         446 : Type.ERR_USERSDISABLED,
1676         447 : Type.ERR_NONICKCHANGE,
1677         448 : Type.ERR_FORBIDDENCHANNEL,
1678         449 : Type.ERR_NOTIMPLEMENTED,
1679         451 : Type.ERR_NOTREGISTERED,
1680         452 : Type.ERR_IDCOLLISION,
1681         453 : Type.ERR_NICKLOST,
1682         455 : Type.ERR_HOSTILENAME,
1683         456 : Type.ERR_ACCEPTFULL,
1684         457 : Type.ERR_ACCEPTEXIST,
1685         458 : Type.ERR_ACCEPTNOT,
1686         459 : Type.ERR_NOHIDING,
1687         460 : Type.ERR_NOTFORHALFOPS,
1688         461 : Type.ERR_NEEDMOREPARAMS,
1689         462 : Type.ERR_ALREADYREGISTERED,
1690         463 : Type.ERR_NOPERMFORHOST,
1691         464 : Type.ERR_PASSWDMISMATCH,
1692         465 : Type.ERR_YOUREBANNEDCREEP,
1693         466 : Type.ERR_YOUWILLBEBANNED,
1694         467 : Type.ERR_KEYSET,
1695         468 : Type.ERR_INVALIDUSERNAME,
1696         469 : Type.ERR_LINKSET,
1697         470 : Type.ERR_LINKCHANNEL,
1698         471 : Type.ERR_CHANNELISFULL,
1699         472 : Type.ERR_UNKNOWNMODE,
1700         473 : Type.ERR_INVITEONLYCHAN,
1701         474 : Type.ERR_BANNEDFROMCHAN,
1702         475 : Type.ERR_BADCHANNELKEY,
1703         476 : Type.ERR_BADCHANMASK,
1704         477 : Type.ERR_NEEDREGGEDNICK,
1705         478 : Type.ERR_BANLISTFULL,
1706         479 : Type.ERR_BADCHANNAME,
1707         480 : Type.ERR_CANNOTKNOCK,
1708         481 : Type.ERR_NOPRIVILEGES,
1709         482 : Type.ERR_CHANOPRIVSNEEDED,
1710         483 : Type.ERR_CANTKILLSERVER,
1711         484 : Type.ERR_RESTRICTED,
1712         485 : Type.ERR_UNIQPRIVSNEEDED,
1713         486 : Type.ERR_NONONREG,
1714         487 : Type.ERR_MSGSERVICES,
1715         488 : Type.ERR_TSLESSCHAN,
1716         489 : Type.ERR_SECUREONLYCHAN,
1717         490 : Type.ERR_ALLMUSTSSL,
1718         491 : Type.ERR_NOOPERHOST,
1719         492 : Type.ERR_NOSERVICEHOST,
1720         493 : Type.ERR_NOFEATURE,
1721         494 : Type.ERR_BADFEATVALUE,
1722         495 : Type.ERR_BADLOGTYPE,
1723         496 : Type.ERR_BADLOGSYS,
1724         497 : Type.ERR_BADLOGVALUE,
1725         498 : Type.ERR_ISOPERLCHAN,
1726         499 : Type.ERR_CHANOWNPRIVNEEDED,
1727         500 : Type.ERR_TOOMANYJOINS,
1728         501 : Type.ERR_UMODEUNKNOWNFLAG,
1729         502 : Type.ERR_USERSDONTMATCH,
1730         503 : Type.ERR_GHOSTEDCLIENT,
1731         504 : Type.ERR_USERNOTONSERV,
1732         511 : Type.ERR_SILELISTFULL,
1733         512 : Type.ERR_TOOMANYWATCH,
1734         513 : Type.ERR_NEEDPONG,
1735         514 : Type.ERR_INVALID_ERROR,
1736         515 : Type.ERR_BADEXPIRE,
1737         516 : Type.ERR_DONTCHEAT,
1738         517 : Type.ERR_DISABLED,
1739         518 : Type.ERR_LONGMASK,
1740         519 : Type.ERR_TOOMANYUSERS,
1741         520 : Type.ERR_OPERONLY,
1742         521 : Type.ERR_LISTSYNTAX,
1743         522 : Type.ERR_WHOSYNTAX,
1744         523 : Type.ERR_WHOLIMEXCEED,
1745         524 : Type.ERR_HELPNOTFOUND,
1746         525 : Type.ERR_REMOTEPFX,
1747         526 : Type.ERR_PFXUNROUTABLE,
1748         531 : Type.ERR_CANTSENDTOUSER,
1749         550 : Type.ERR_BADHOSTMASK,
1750         551 : Type.ERR_HOSTUNAVAIL,
1751         552 : Type.ERR_USINGSLINE,
1752         553 : Type.ERR_STATSSLINE,
1753         560 : Type.ERR_NOTLOWEROPLEVEL,
1754         561 : Type.ERR_NOTMANAGER,
1755         562 : Type.ERR_CHANSECURED,
1756         563 : Type.ERR_UPASSSET,
1757         564 : Type.ERR_UPASSNOTSET,
1758         566 : Type.ERR_NOMANAGER,
1759         567 : Type.ERR_UPASS_SAME_APASS,
1760         568 : Type.ERR_LASTERROR,
1761         597 : Type.RPL_REAWAY,
1762         598 : Type.RPL_GONEAWAY,
1763         599 : Type.RPL_NOTAWAY,
1764         600 : Type.RPL_LOGON,
1765         601 : Type.RPL_LOGOFF,
1766         602 : Type.RPL_WATCHOFF,
1767         603 : Type.RPL_WATCHSTAT,
1768         604 : Type.RPL_NOWON,
1769         605 : Type.RPL_NOWFF,
1770         606 : Type.RPL_WATCHLIST,
1771         607 : Type.RPL_ENDOFWATCHLIST,
1772         608 : Type.RPL_WATCHCLEAR,
1773         609 : Type.RPL_NOWISAWAY,
1774         610 : Type.RPL_MAPMORE,
1775         611 : Type.RPL_ISLOCOP,
1776         612 : Type.RPL_ISNOTOPER,
1777         613 : Type.RPL_ENDOFISOPER,
1778         615 : Type.RPL_WHOISMODES,
1779         616 : Type.RPL_WHOISHOST,
1780         617 : Type.RPL_DCCSTATUS,
1781         618 : Type.RPL_DCCLIST,
1782         619 : Type.RPL_ENDOFDCCLIST,
1783         620 : Type.RPL_DCCINFO,
1784         621 : Type.RPL_RULES,
1785         622 : Type.RPL_ENDOFRULES,
1786         623 : Type.RPL_MAPMORE,
1787         624 : Type.RPL_OMOTDSTART,
1788         625 : Type.RPL_OMOTD,
1789         626 : Type.RPL_ENDOFO,
1790         630 : Type.RPL_SETTINGS,
1791         631 : Type.RPL_ENDOFSETTINGS,
1792         640 : Type.RPL_DUMPING,
1793         641 : Type.RPL_DUMPRPL,
1794         642 : Type.RPL_EODUMP,
1795         659 : Type.RPL_SPAMCMDFWD,
1796         660 : Type.RPL_TRACEROUTE_HOP,
1797         661 : Type.RPL_TRACEROUTE_START,
1798         662 : Type.RPL_MODECHANGEWARN,
1799         663 : Type.RPL_CHANREDIR,
1800         664 : Type.RPL_SERVMODEIS,
1801         665 : Type.RPL_OTHERUMODEIS,
1802         666 : Type.RPL_ENDOF_GENERIC,
1803         670 : Type.RPL_STARTTLS,
1804         671 : Type.RPL_WHOISSECURE,
1805         672 : Type.RPL_WHOISREALIP,
1806         673 : Type.RPL_CANNOTSETMODES,
1807         674 : Type.RPL_WHOISYOURID,
1808         678 : Type.RPL_LUSERSTAFF,
1809         679 : Type.RPL_TIMEONSERVERIS,
1810         682 : Type.RPL_NETWORKS,
1811         687 : Type.RPL_YOURLANGUAGEIS,
1812         688 : Type.RPL_LANGUAGE,
1813         689 : Type.RPL_WHOISSTAFF,
1814         690 : Type.RPL_WHOISLANGUAGE,
1815         691 : Type.ERR_STARTTLS,
1816         702 : Type.RPL_COMMANDS,
1817         703 : Type.RPL_COMMANDSEND,
1818         704 : Type.RPL_HELPSTART,
1819         705 : Type.RPL_HELPTXT,
1820         706 : Type.RPL_ENDOFHELP,
1821         707 : Type.ERR_TARGCHANGE,
1822         708 : Type.RPL_ETRACEFULL,
1823         709 : Type.RPL_ETRACE,
1824         710 : Type.RPL_KNOCK,
1825         711 : Type.RPL_KNOCKDLVR,
1826         712 : Type.ERR_TOOMANYKNOCK,
1827         713 : Type.ERR_CHANOPEN,
1828         714 : Type.ERR_KNOCKONCHAN,
1829         715 : Type.RPL_INVITETHROTTLE,
1830         716 : Type.RPL_TARGUMODEG,
1831         717 : Type.RPL_TARGNOTIFY,
1832         718 : Type.RPL_UMODEGMSG,
1833         720 : Type.RPL_OMOTDSTART,
1834         721 : Type.RPL_OMOTD,
1835         722 : Type.RPL_ENDOFOMOTD,
1836         723 : Type.ERR_NOPRIVS,
1837         724 : Type.RPL_TESTMASK,
1838         725 : Type.RPL_TESTLINE,
1839         726 : Type.RPL_NOTESTLINE,
1840         727 : Type.RPL_TESTMASKGECOS,
1841         728 : Type.RPL_QUIETLIST,
1842         729 : Type.RPL_ENDOFQUIETLIST,
1843         730 : Type.RPL_MONONLINE,
1844         731 : Type.RPL_MONOFFLINE,
1845         732 : Type.RPL_MONLIST,
1846         733 : Type.RPL_ENDOFMONLIST,
1847         734 : Type.ERR_MONLISTFULL,
1848         740 : Type.RPL_RSACHALLENGE2,
1849         741 : Type.RPL_ENDOFRSACHALLENGE2,
1850         742 : Type.ERR_MLOCKRESTRICTED,
1851         743 : Type.ERR_INVALIDBAN,
1852         744 : Type.ERR_TOPICLOCK,
1853         750 : Type.RPL_SCANMATCHED,
1854         751 : Type.RPL_SCANUMODES,
1855         759 : Type.RPL_ETRACEEND,
1856         760 : Type.RPL_WHOISKEYVALUE,
1857         761 : Type.RPL_KEYVALUE,
1858         762 : Type.RPL_METADATAEND,
1859         764 : Type.ERR_METADATALIMIT,
1860         765 : Type.ERR_TARGETINVALID,
1861         766 : Type.ERR_NOMATCHINGKEY,
1862         767 : Type.ERR_KEYINVALID,
1863         768 : Type.ERR_KEYNOTSET,
1864         769 : Type.ERR_KEYNOPERMISSION,
1865         771 : Type.RPL_XINFO,
1866         773 : Type.RPL_XINFOSTART,
1867         774 : Type.RPL_XINFOEND,
1868         802 : Type.RPL_CHECK,
1869         900 : Type.RPL_LOGGEDIN,
1870         901 : Type.RPL_LOGGEDOUT,
1871         902 : Type.ERR_NICKLOCKED,
1872         903 : Type.RPL_SASLSUCCESS,
1873         904 : Type.ERR_SASLFAIL,
1874         905 : Type.ERR_SASLTOOLONG,
1875         906 : Type.ERR_SASLABORTED,
1876         907 : Type.ERR_SASLALREADY,
1877         908 : Type.RPL_SASLMECHS,
1878         911 : Type.ENDOFCHANNELACCLIST,
1879         960 : Type.ENDOFMODELIST,
1880         961 : Type.MODELIST,
1881         931 : Type.BOTSNOTWELCOME,
1882         926 : Type.CHANNELFORBIDDEN,
1883         936 : Type.ERR_WORDFILTERED,
1884         940 : Type.ENDOFSPAMFILTERLIST,
1885         941 : Type.SPAMFILTERLIST,
1886         945 : Type.NICKUNLOCKED,
1887         946 : Type.NICKNOTLOCKED,
1888         972 : Type.ERR_CANNOTDOCOMMAND,
1889         973 : Type.ERR_CANNOTCHANGEUMODE,
1890         974 : Type.ERR_CANNOTCHANGECHANMODE,
1891         975 : Type.RPL_LOADEDMODULE,
1892         976 : Type.ERR_CANNOTSENDTONICK,
1893         977 : Type.ERR_UNKNOWNSERVERMODE,
1894         979 : Type.ERR_SERVERMODELOCK,
1895         980 : Type.ERR_BADCHARENCODING,
1896         981 : Type.ERR_TOOMANYLANGUAGES,
1897         982 : Type.ERR_NOLANGUAGE,
1898         983 : Type.ERR_TEXTTOOSHORT,
1899         999 : Type.ERR_NUMERIC_ERR,
1900     ];
1901 
1902     /++
1903         Delta typenum mappings for servers running the `UnrealIRCd` daemon.
1904 
1905         - https://www.unrealircd.org
1906      +/
1907     static immutable Type[975] unreal =
1908     [
1909         6 : Type.RPL_MAP,
1910         7 : Type.RPL_MAPEND,
1911         210 : Type.RPL_STATSHELP,
1912         220 : Type.RPL_STATSBLINE,
1913         222 : Type.RPL_SQLINE_NICK,
1914         223 : Type.RPL_STATSGLINE,
1915         224 : Type.RPL_STATSTLINE,
1916         225 : Type.RPL_STATSELINE,
1917         226 : Type.RPL_STATSNLINE,
1918         227 : Type.RPL_STATSVLINE,
1919         228 : Type.RPL_STATSBANVER,
1920         232 : Type.RPL_RULES,
1921         247 : Type.RPL_STATSXLINE,
1922         250 : Type.RPL_STATSCONN,
1923         290 : Type.RPL_HELPHDR,
1924         291 : Type.RPL_HELPOP,
1925         292 : Type.RPL_HELPTLR,
1926         293 : Type.RPL_HELPHLP,
1927         294 : Type.RPL_HELPFWD,
1928         295 : Type.RPL_HELPIGN,
1929         307 : Type.RPL_WHOISREGNICK,
1930         308 : Type.RPL_RULESSTART,
1931         309 : Type.RPL_ENDOFRULES,
1932         310 : Type.RPL_WHOISHELPOP,
1933         320 : Type.RPL_WHOISSPECIAL,
1934         334 : Type.RPL_LISTSYNTAX,
1935         335 : Type.RPL_WHOISBOT,
1936         378 : Type.RPL_WHOISHOST,
1937         379 : Type.RPL_WHOISMODES,
1938         386 : Type.RPL_QLIST,
1939         387 : Type.RPL_ENDOFQLIST,
1940         388 : Type.RPL_ALIST,
1941         434 : Type.ERR_NORULES,
1942         435 : Type.ERR_SERVICECONFUSED,
1943         438 : Type.ERR_ONLYSERVERSCANCHANGE,
1944         470 : Type.ERR_LINKCHANNEL,
1945         477 : Type.ERR_NEEDREGGEDNICK,
1946         479 : Type.ERR_LINKFAIL,
1947         480 : Type.ERR_CANNOTKNOCK,
1948         484 : Type.ERR_ATTACKDENY,
1949         485 : Type.ERR_KILLDENY,
1950         486 : Type.ERR_HTMDISABLED,         // CONFLICT ERR_NONONREG
1951         487 : Type.ERR_NOTFORUSERS,
1952         488 : Type.ERR_HTMDISABLED,         // again?
1953         489 : Type.ERR_SECUREONLYCHAN,      // AKA ERR_SSLONLYCHAN
1954         490 : Type.ERR_ALLMUSTSSL,          // CONFLICT ERR_NOSWEAR
1955         492 : Type.ERR_NOCTCP,
1956         500 : Type.ERR_TOOMANYJOINS,
1957         518 : Type.ERR_NOINVITE,
1958         519 : Type.ERR_ADMONLY,
1959         520 : Type.ERR_OPERONLY,
1960         524 : Type.ERR_OPERSPVERIFY,
1961         610 : Type.RPL_MAPMORE,
1962         972 : Type.ERR_CANNOTDOCOMMAND,
1963         974 : Type.ERR_CANNOTCHANGECHANMODE,
1964     ];
1965 
1966     /++
1967         Delta typenum mappings for servers running the `ircu` (Undernet) daemon.
1968 
1969         - http://coder-com.undernet.org
1970      +/
1971     static immutable Type[569] ircu =
1972     [
1973         15 : Type.RPL_MAP,
1974         16 : Type.RPL_MAPMORE,
1975         17 : Type.RPL_MAPEND,
1976         222 : Type.RPL_STATSJLINE,
1977         228 : Type.RPL_STATSQLINE,
1978         238 : Type.RPL_STATSFLINE,
1979         246 : Type.RPL_STATSTLINE,
1980         247 : Type.RPL_STATSGLINE,
1981         248 : Type.RPL_STATSULINE,
1982         250 : Type.RPL_STATSCONN,
1983         270 : Type.RPL_PRIVS,
1984         275 : Type.RPL_STATSDLINE,
1985         276 : Type.RPL_STATSRLINE,
1986         281 : Type.RPL_ENDOFGLIST,
1987         282 : Type.RPL_JUPELIST,
1988         283 : Type.RPL_ENDOFJUPELIST,
1989         284 : Type.RPL_FEATURE,
1990         330 : Type.RPL_WHOISACCOUNT,
1991         334 : Type.RPL_LISTUSAGE,
1992         338 : Type.RPL_WHOISACTUALLY,
1993         391 : Type.RPL_TIME,
1994         437 : Type.ERR_BANNICKCHANGE,
1995         438 : Type.ERR_NICKTOOFAST,
1996         468 : Type.ERR_INVALIDUSERNAME,
1997         477 : Type.ERR_NEEDREGGEDNICK,
1998         493 : Type.ERR_NOFEATURE,
1999         494 : Type.ERR_BADFEATVALUE,
2000         495 : Type.ERR_BADLOGTYPE,
2001         512 : Type.ERR_NOSUCHGLINE,
2002         514 : Type.ERR_INVALID_ERROR,
2003         518 : Type.ERR_LONGMASK,
2004         519 : Type.ERR_TOOMANYUSERS,
2005         520 : Type.ERR_MASKTOOWIDE,
2006         524 : Type.ERR_QUARANTINED,
2007         568 : Type.ERR_LASTERROR,
2008     ];
2009 
2010     /++
2011         Delta typenum mappings for servers running the `aircd` (?) daemon.
2012 
2013         "After AnotherNet had become a commercial and proprietary-client chat
2014         network, the former users of AnotherNet's #trax decided to found their
2015         own network - "where free speech and ideas would be able to run
2016         unbounded through the pastures of #trax and #coders". They use the
2017         "`aircd`" IRC daemon, coded by an ex-member of the demoscene, simon
2018         kirby."
2019      +/
2020     static immutable Type[471] aircd =
2021     [
2022         210 : Type.RPL_STATS,
2023         274 : Type.RPL_ENDNOTIFY,
2024         285 : Type.RPL_CHANINFO_HANDLE,
2025         286 : Type.RPL_CHANINFO_USERS,
2026         287 : Type.RPL_CHANINFO_CHOPS,
2027         288 : Type.RPL_CHANINFO_VOICES,
2028         289 : Type.RPL_CHANINFO_AWAY,
2029         290 : Type.RPL_CHANINFO_OPERS,
2030         291 : Type.RPL_CHANINFO_BANNED,
2031         292 : Type.RPL_CHANINFO_BANS,
2032         293 : Type.RPL_CHANINFO_INVITE,
2033         294 : Type.RPL_CHANINFO_INVITES,
2034         295 : Type.RPL_CHANINFO_KICKS,
2035         308 : Type.RPL_NOTIFYACTION,
2036         309 : Type.RPL_NICKTRACE,
2037         377 : Type.RPL_KICKEXPIRED,
2038         378 : Type.RPL_BANEXPIRED,
2039         379 : Type.RPL_KICKLINKED,
2040         380 : Type.RPL_BANLINKED,
2041         470 : Type.ERR_KICKEDFROMCHAN,
2042     ];
2043 
2044     /++
2045         Delta typenum mappings for servers adhering to the `RFC1459` draft.
2046 
2047         - https://tools.ietf.org/html/rfc1459
2048      +/
2049     static immutable Type[502] rfc1459 =
2050     [
2051         214 : Type.RPL_STATSNLINE,
2052         217 : Type.RPL_STATSQLINE,
2053         232 : Type.RPL_ENDOFSERVICES,
2054         316 : Type.RPL_WHOISCHANOP, // deprecated
2055         391 : Type.RPL_TIME,
2056         492 : Type.ERR_NOSERVICEHOST,
2057         501 : Type.ERR_UMODEUNKNOWNFLAG,
2058     ];
2059 
2060     /++
2061         Delta typenum mappings for servers adhering to the `RFC2812` draft.
2062 
2063         - https://tools.ietf.org/html/rfc2812
2064      +/
2065     static immutable Type[485] rfc2812 =
2066     [
2067         240 : Type.RPL_STATSVLINE,
2068         246 : Type.RPL_STATSPING,
2069         247 : Type.RPL_STATSBLINE,
2070         250 : Type.RPL_STATSDLINE,
2071         262 : Type.RPL_TRACEEND,
2072         325 : Type.RPL_UNIQOPIS,
2073         437 : Type.ERR_UNAVAILRESOURCE,
2074         477 : Type.ERR_NOCHANMODES,
2075         484 : Type.ERR_RESTRICTED,
2076     ];
2077 
2078     /++
2079         Delta typenum mappings for servers running the `IRCD-Hybrid` daemon.
2080 
2081         - http://www.ircd-hybrid.org
2082      +/
2083     static immutable Type[716] hybrid =
2084     [
2085         220 : Type.RPL_STATSPLINE,
2086         224 : Type.RPL_STATSFLINE,
2087         225 : Type.RPL_STATSDLINE,
2088         226 : Type.RPL_STATSALINE,
2089         245 : Type.RPL_STATSSLINE,      // CONFLICT: Type.RPL_STATSTLINE
2090         246 : Type.RPL_STATSSERVICE,    // CONFLICT: Type.RPL_STATSULINE
2091         247 : Type.RPL_STATSXLINE,
2092         249 : Type.RPL_STATSDEBUG,
2093         276 : Type.RPL_WHOISCERTFP,     // oftc-hybrid?
2094         335 : Type.RPL_WHOISTEXT,
2095         336 : Type.RPL_INVITELIST,
2096         337 : Type.RPL_ENDOFINVITELIST, // CONFLICT: Type.RPL_WHOISTEXT
2097         344 : Type.RPL_QUIETLIST,       // oftc
2098         345 : Type.RPL_ENDOFQUIETLIST,  // CONFLICT: Type.RPL_INVITED, oftc
2099         386 : Type.RPL_RSACHALLENGE,
2100         396 : Type.RPL_VISIBLEHOST,
2101         408 : Type.ERR_NOCTRLSONCHAN,
2102         479 : Type.ERR_BADCHANNAME,
2103         480 : Type.ERR_SSLONLYCHAN,     // deprecated
2104         484 : Type.ERR_DESYNC,
2105         485 : Type.ERR_CHANBANREASON,
2106         492 : Type.ERR_NOCTCP,
2107         503 : Type.ERR_GHOSTEDCLIENT,
2108         524 : Type.ERR_HELPNOTFOUND,
2109         715 : Type.ERR_TOOMANYINVITE,
2110     ];
2111 
2112     /++
2113         Delta typenum mappings for servers running the `Solanum` daemon.
2114 
2115         - https://github.com/solanum-ircd/solanum
2116      +/
2117     static immutable Type[250] solanum =
2118     [
2119         249 : Type.RPL_STATSPLINE,
2120     ];
2121 
2122     /++
2123         Delta typenum mappings for servers running the `Bahamut` daemon
2124         (DALnet).
2125 
2126         - https://www.dal.net/?page=bahamut
2127      +/
2128     static immutable Type[621] bahamut =
2129     [
2130         220 : Type.RPL_STATSBLINE,
2131         222 : Type.RPL_STATSBLINE,
2132         223 : Type.RPL_STATSELINE,
2133         224 : Type.RPL_STATSFLINE,
2134         225 : Type.RPL_STATSCLONE,      // DEPRECATED CONFLICT: Type.RPL_STATSZLINE
2135         226 : Type.RPL_STATSCOUNT,
2136         227 : Type.RPL_STATSGLINE,
2137         245 : Type.RPL_STATSSLINE,
2138         275 : Type.RPL_USINGSSL,
2139         307 : Type.RPL_WHOISREGNICK,
2140         308 : Type.RPL_WHOISADMIN,
2141         309 : Type.RPL_WHOISADMIN,      // duplicate?
2142         310 : Type.RPL_WHOISSVCMSG,
2143         334 : Type.RPL_COMMANDSYNTAX,
2144         338 : Type.RPL_WHOISACTUALLY,
2145         408 : Type.ERR_NOCOLORSONCHAN,
2146         435 : Type.ERR_BANONCHAN,
2147         468 : Type.ERR_ONLYSERVERSCANCHANGE,
2148         477 : Type.ERR_NEEDREGGEDNICK,
2149         484 : Type.ERR_DESYNC,
2150         487 : Type.ERR_MSGSERVICES,
2151         488 : Type.ERR_NOSSL,
2152         493 : Type.ERR_NOSHAREDCHAN,
2153         494 : Type.ERR_OWNMODE,
2154         512 : Type.ERR_TOOMANYWATCH,
2155         514 : Type.ERR_TOOMANYDCC,
2156         521 : Type.ERR_LISTSYNTAX,
2157         617 : Type.RPL_DCCSTATUS,
2158         619 : Type.RPL_ENDOFDCCLIST,
2159         620 : Type.RPL_DCCINFO,
2160     ];
2161 
2162     /++
2163         Delta typenum mappings for servers running the `snircd` daemon
2164         (QuakeNet), based on `ircu`.
2165 
2166         - https://development.quakenet.org
2167      +/
2168     static immutable Type[554] snircd =
2169     [
2170         285 : Type.RPL_NEWHOSTIS,
2171         286 : Type.RPL_CHKHEAD,
2172         287 : Type.RPL_CHANUSER,
2173         288 : Type.RPL_PATCHHEAD,
2174         289 : Type.RPL_PATCHCON,
2175         290 : Type.RPL_DATASTR,
2176         291 : Type.RPL_ENDOFCHECK,
2177         485 : Type.ERR_ISREALSERVICE,
2178         486 : Type.ERR_ACCOUNTONLY,
2179         553 : Type.ERR_STATSSLINE,
2180     ];
2181 
2182     /++
2183         Delta typenum mappings for servers running the `Nefarious` or
2184         `Nefarious2` daemons, based on `ircu`.
2185 
2186         - https://github.com/evilnet/nefarious
2187         - https://github.com/evilnet/nefarious2
2188      +/
2189     static immutable Type[976] nefarious =
2190     [
2191         220 : Type.RPL_STATSWLINE,
2192         292 : Type.ERR_SEARCHNOMATCH,
2193         316 : Type.RPL_WHOISPRIVDEAF,
2194         320 : Type.RPL_WHOISWEBIRC,
2195         335 : Type.RPL_WHOISACCOUNTONLY,
2196         336 : Type.RPL_WHOISBOT,
2197         339 : Type.RPL_WHOISMARKS,
2198         386 : Type.RPL_IRCOPSHEADER,
2199         387 : Type.RPL_IRCOPS,
2200         388 : Type.RPL_ENDOFIRCOPS,
2201         521 : Type.ERR_NOSUCHGLINE,
2202         568 : Type.RPL_NOMOTD,
2203         617 : Type.RPL_WHOISSSLFP,
2204         975 : Type.ERR_LASTERROR,
2205     ];
2206 
2207     /++
2208         Delta typenum mappings for `RusNet` servers. Unsure of what daemon they
2209         run.
2210 
2211         - http://www.rus-net.org
2212      +/
2213     static immutable Type[501] rusnet =
2214     [
2215         222 : Type.RPL_CODEPAGE,
2216         223 : Type.RPL_CHARSET,
2217         327 : Type.RPL_WHOISHOST,
2218         468 : Type.ERR_NOCODEPAGE,
2219         470 : Type.ERR_7BIT,
2220         479 : Type.ERR_NOCOLOR,
2221         480 : Type.ERR_NOWALLOP,
2222         486 : Type.ERR_RLINED,
2223         500 : Type.ERR_NOREHASHPARAM,
2224     ];
2225 
2226     /++
2227         Delta typenum mappings for `Rizon` network servers. Supposedly they use
2228         a mixture of Hybrid typenums, plus a few of their own.
2229 
2230         - https://www.rizon.net
2231      +/
2232     static immutable Type[716] rizon =
2233     [
2234         227 : Type.RPL_STATSBLINE,
2235         672 : Type.RPL_WHOISREALIP,
2236         715 : Type.RPL_INVITETHROTTLE,
2237     ];
2238 
2239     /++
2240         Delta typenum mappings for `austHex` AUSTNet Development servers.
2241 
2242         - https://sourceforge.net/projects/austhex
2243      +/
2244     static immutable Type[521] austHex =
2245     [
2246         240 : Type.RPL_STATSXLINE,
2247         307 : Type.RPL_SUSERHOST,
2248         309 : Type.RPL_WHOISHELPER,
2249         310 : Type.RPL_WHOISSERVICE,
2250         320 : Type.RPL_WHOISVIRT,
2251         357 : Type.RPL_MAP,
2252         358 : Type.RPL_MAPMORE,
2253         359 : Type.RPL_MAPEND,
2254         377 : Type.RPL_SPAM,            // deprecated
2255         378 : Type.RPL_MOTD,
2256         380 : Type.RPL_YOURHELPER,
2257         434 : Type.ERR_SERVICENAMEINUSE,
2258         480 : Type.ERR_NOULINE,
2259         503 : Type.ERR_VWORLDWARN,
2260         520 : Type.ERR_WHOTRUNC,        // deprecated
2261     ];
2262 
2263     /++
2264         Delta typenum mappings for the `IRCnet` network of servers. Unsure of
2265         what server daemon they run.
2266 
2267         - http://www.ircnet.org
2268      +/
2269     static immutable Type[489] ircNet =
2270     [
2271         245 : Type.RPL_STATSSLINE,
2272         248 : Type.RPL_STATSDEFINE,
2273         274 : Type.RPL_STATSDELTA,
2274         344 : Type.RPL_REOPLIST,
2275         345 : Type.RPL_ENDOFREOPLIST,
2276         438 : Type.ERR_DEAD,
2277         487 : Type.ERR_CHANTOORECENT,
2278         488 : Type.ERR_TSLESSCHAN,
2279     ];
2280 
2281     /++
2282         Delta typenum mappings for servers running the `PTlink` daemon.
2283 
2284         - https://sourceforge.net/projects/ptlinksoft
2285      +/
2286     static immutable Type[616] ptlink =
2287     [
2288         247 : Type.RPL_STATSXLINE,
2289         484 : Type.ERR_DESYNC,
2290         485 : Type.ERR_CANTKICKADMIN,
2291         615 : Type.RPL_MAPMORE,
2292     ];
2293 
2294     /++
2295         Delta typenum mappings for servers running the `InspIRCd` daemon.
2296 
2297         - http://www.inspircd.org
2298      +/
2299     static immutable Type[976] inspIRCd =
2300     [
2301         270 : Type.RPL_MAPUSERS,
2302         304 : Type.RPL_SYNTAX,
2303         379 : Type.RPL_WHOWASIP,  // also encountered as Type.RPL_WHOISMODES?
2304         495 : Type.ERR_DELAYREJOIN,
2305         501 : Type.ERR_UNKNOWNSNOMASK,
2306         702 : Type.RPL_COMMANDS,
2307         703 : Type.RPL_COMMANDSEND,
2308         953 : Type.ENDOFEXEMPTOPSLIST,
2309         972 : Type.ERR_CANTUNLOADMODULE,
2310         974 : Type.ERR_CANTLOADMODULE,
2311         975 : Type.RPL_LOADEDMODULE
2312     ];
2313 
2314     /++
2315         Delta typenum mapping for servers running the `ultimate` daemon.
2316         Based off of `Bahamut`.
2317      +/
2318     static immutable Type[624] ultimate =
2319     [
2320         275 : Type.RPL_USINGSSL,
2321         386 : Type.RPL_IRCOPS,
2322         387 : Type.RPL_ENDOFIRCOPS,
2323         434 : Type.ERR_NORULES,
2324         610 : Type.RPL_ISOPER,
2325         615 : Type.RPL_WHOISMODES,
2326         616 : Type.RPL_WHOISHOST,
2327         617 : Type.RPL_WHOISBOT,
2328         619 : Type.RPL_WHOWASHOST,
2329         620 : Type.RPL_RULESSTART,
2330         621 : Type.RPL_RULES,
2331         622 : Type.RPL_ENDOFRULES,
2332         623 : Type.RPL_MAPMORE,
2333     ];
2334 
2335     /++
2336         Delta typenum mappings extending `ircu` typenums, for UnderNet.
2337 
2338         - https://github.com/UndernetIRC/ircu2
2339      +/
2340     static immutable Type[490] undernet =
2341     [
2342         396 : Type.RPL_HOSTHIDDEN,
2343         484 : Type.ERR_ISCHANSERVICE,
2344         489 : Type.ERR_VOICENEEDED,
2345     ];
2346 
2347     /++
2348         Delta typenum mapping for servers running the `ratbox` daemon. It is
2349         primarily used on EFnet.
2350 
2351         - https://www.ratbox.org
2352      +/
2353     static immutable Type[716] ratBox =
2354     [
2355         480 : Type.ERR_THROTTLE,
2356         485 : Type.ERR_BANNEDNICK,      // deprecated
2357         702 : Type.RPL_MODLIST,
2358         703 : Type.RPL_ENDOFMODLIST,
2359         715 : Type.ERR_KNOCKDISABLED,
2360     ];
2361 
2362     /++
2363         Delta typenum mappings for servers running the `charybdis` daemon.
2364 
2365         - https://github.com/charybdis-ircd/charybdis
2366      +/
2367     static immutable Type[495] charybdis =
2368     [
2369         492 : Type.ERR_CANNOTSENDTOUSER,
2370         494 : Type.ERR_OWNMODE,
2371     ];
2372 
2373     /++
2374         Delta typenum mappings for servers running the `sorircd` daemon
2375         (SorceryNet).
2376 
2377         - http://www.nongnu.org/snservices/sorircd.html
2378      +/
2379     static immutable Type[326] sorircd =
2380     [
2381         325 : Type.RPL_CHANNELMLOCKIS,  // deprecated
2382     ];
2383 
2384     /*
2385     static immutable Type[321] anothernet =
2386     [
2387         320 : Type.RPL_WHOIS_HIDDEN,
2388     ];
2389 
2390     static immutable Type[392] bdqIRCd =
2391     [
2392         391 : Type.RPL_TIME,
2393     ];
2394 
2395     static immutable Type[488] chatIRCd =
2396     [
2397         487 : Type.ERR_NONONSSL,
2398     ];
2399 
2400     static immutable Type[515] irch =
2401     [
2402         514 : Type.ERR_NOSUCHJUPE,
2403     ];
2404 
2405     static immutable Type[672] ithildin =
2406     [
2407         672 : Type.RPL_UNKNOWNMODES,
2408     ];
2409     */
2410 }
2411 
2412 
2413 // IRCChannel
2414 /++
2415     Aggregate personifying an IRC channel and its state.
2416 
2417     An IRC channel may have a topic, a creation date, and one or more *modes*.
2418     Modes define how the channel behaves and how it treats its users, including
2419     which ones have operator and voice status, as well as which are banned, and more.
2420  +/
2421 struct IRCChannel
2422 {
2423     /++
2424         A channel mode.
2425 
2426         Some modes overwrite themselves; a channel may be `+i` or `-i`, never
2427         `i` twice. Others stack; a channel may have an arbitrary number of `b`
2428         bans. We try our best to support both.
2429      +/
2430     static struct Mode
2431     {
2432         /++
2433             The character that implies this [Mode] (`i`, `z`, `l` ...).
2434          +/
2435         char modechar;
2436 
2437         /++
2438             The data associated with the [Mode], if applicable. This is often a
2439             number, such as what `l` takes (join limit).
2440          +/
2441         string data;
2442 
2443         /++
2444             The user associated with the [Mode], when it is not just [Mode.data|data].
2445          +/
2446         IRCUser user;
2447 
2448         /++
2449             The channel this mode refers to, where applicable.
2450          +/
2451         string channel;
2452 
2453         /++
2454             Users that are explicitly exempt from the [Mode].
2455          +/
2456         IRCUser[] exceptions;
2457 
2458         /++
2459             Whether or not this [Mode] should be considered to be its own antithesis.
2460          +/
2461         bool negated;
2462 
2463         /++
2464             Compare two [Mode]s with each other to see if they are both of the
2465             same type, as well as having the same [data] and/or [user].
2466 
2467             Params:
2468                 that = Other [Mode] to compare this one with.
2469 
2470             Returns:
2471                 `true` if the [Mode]s match, `false` if not.
2472          +/
2473         auto opEquals(const Mode that) const pure @safe nothrow @nogc
2474         {
2475             // Ignore exemptions when comparing Modes
2476             immutable charMatch = (this.modechar == that.modechar);
2477             immutable dataMatch = (this.data == that.data);
2478             immutable userMatch = (this.user == that.user);  // IRCUser.opEquals
2479             immutable chanMatch = (this.channel == that.channel);
2480 
2481             immutable match = (charMatch && dataMatch && userMatch && chanMatch);
2482             return negated ? !match : match;
2483         }
2484 
2485         /++
2486             Produces a hash for this [Mode].
2487 
2488             Returns:
2489                 A hash.
2490          +/
2491         auto toHash() const pure @safe
2492         {
2493             import std.conv : text;
2494             return text(modechar, data, user.hashOf, channel, negated).hashOf;
2495         }
2496     }
2497 
2498     /++
2499         The channel name.
2500      +/
2501     string name;
2502 
2503     /++
2504         The current topic of the channel, as set by operators.
2505      +/
2506     string topic;
2507 
2508     /++
2509         The current non-[data]-sporting [Mode]s of the channel.
2510      +/
2511     string modechars;
2512 
2513     /++
2514         Array of all [Mode]s that are not simply represented in [modechars].
2515      +/
2516     Mode[] modes;
2517 
2518     /++
2519         Associative array of all the nicknames inhabiting the channel.
2520      +/
2521     bool[string] users;
2522 
2523     /++
2524         Associative array of nicknames with a prefixing channel mode (operator,
2525         halfops, voiced, ...) keyed by modechar.
2526      +/
2527     bool[string][char] mods;
2528 
2529     /++
2530         Template to deduplicate code for mods shorthands.
2531 
2532         Params:
2533             prefix = Mode character.
2534 
2535         Returns:
2536             A `bool[string]` hashmap of all users with the given mode character
2537             as keys.
2538      +/
2539     ref bool[string] modsShorthand(char prefix)()
2540     {
2541         auto modsOp = prefix in mods;
2542 
2543         if (!modsOp)
2544         {
2545             this.mods[prefix][string.init] = false;
2546             modsOp = prefix in this.mods;
2547             (*modsOp).remove(string.init);
2548         }
2549 
2550         return *modsOp;
2551     }
2552 
2553     /++
2554         Array of channel operators.
2555      +/
2556     alias ops = modsShorthand!'o';
2557 
2558     /++
2559         Array of channel halfops.
2560      +/
2561     alias halfops = modsShorthand!'h';
2562 
2563     /++
2564         Array of voiced channel users.
2565      +/
2566     alias voiced = modsShorthand!'v';
2567 
2568     /++
2569         When the channel was created, expressed in UNIX time.
2570      +/
2571     long created;
2572 }
2573 
2574 
2575 // IRCClient
2576 /++
2577     Aggregate collecting all the relevant settings, options and state needed for
2578     a connection to an IRC server.
2579 
2580     Many fields are transient and unfit to be saved to disk.
2581  +/
2582 struct IRCClient
2583 {
2584     /++
2585         Client nickname.
2586      +/
2587     string nickname; // = "kameloso";
2588 
2589     /++
2590         Client "user".
2591      +/
2592     string user; // = "kameloso";
2593 
2594     /++
2595         Client GECOS/"real name".
2596      +/
2597     string realName; // = "kameloso IRC bot";
2598 
2599     @Unserialisable
2600     {
2601         /++
2602             The original client nickname before connecting, in case it changed.
2603          +/
2604         string origNickname;
2605 
2606         /++
2607             Client IDENT identifier. Defaults to "~`user`".
2608             Unused but keep for future expansion.
2609          +/
2610         string ident;
2611 
2612         version(TwitchSupport)
2613         {
2614             /++
2615                 Our Twitch display name or alias.
2616              +/
2617             string displayName;
2618         }
2619 
2620         /++
2621             The current modechars active on the client (e.g. "ix");
2622          +/
2623         string modes;
2624     }
2625 }