CTCP draft from 1997 (moribund?)
The organization is poor. Consider, for instance, 3.1.2 - one of the first commands documented. The syntax for <nickname> is given in an earlier section, so you have to go and look at that rather than having it to hand on the same page; similarly the meaning of the reply codes needs to be looked up in a later section.
Compare this with (for instance) RFC2616 where relevant bits of syntax are given closer to the points they are actually required (look at 14.1 for an example) or RFC977 where the standard responses for each command are given numerically and with explanations in the documentation for that command. (This duplicates information, but at a line per response, I think the benefit fairly clearly outweighs the cost.)
Letter Case. It doesn't appear to be stated whether command name are case sensitive or case-insensitive. In fact the server I have to hand throws away bit 5 when comparing them, so it would appear that they are supposed to be case-insensitive.
Reply Syntax. 2.4 tells you that the every reply should have the nickname of the target immediately after the 3-digit code, but this is not reflected either in the EBNF in 2.3.1 nor the reply syntax list in section 5.
Perhaps these should be in the "flaws in the server" section; but it's hard to tell whether a difference indicates an RFC that doesn't correctly documented the protocol, or a server that doesn't correctly implement it.
It's possible that I've missed some bit of detail in the RFC that clears up these differences. If so, please let me know.
The documentation for USER tells you that it has this syntax:
USER <user> <mode> <unused> <realname>
...and gives some examples:
USER guest 0 * :Ronnie Reagan ; User registering themselves with a
username of "guest" and real name
"Ronnie Reagan".
In fact the comments in the server thinks the second field (<mode>) should be a hostname, but the code ignores it; in practice it doesn't pay much attention to the <user> field either, instead using the ident response.
The <realname> field does appear to do what it says on the tin.
Something the RFC doesn't tell you is that if you don't respond to a PING, then the server will actually silently hold up the response to (e.g.) USER until the PONG is received. This seems slightly odd behaviour but perhaps there is a good reason for it.
Also the RFC claims that the arguments to PING are server names, but in fact what you get (at least some of the time) is just a number (probably a time_t). As far as I can tell what you should do with a PING is immediately send a PONG with the same list of arguments.
(This refers to ircu2.10.10.)
#define MSG_NICK "NICK" /* NICK */
This is silly. The NICK command is not going to change (and if it did you'd still need a NICK command for compatibility with old clients). Introducing a #define is pointless.
#define MSG_END_OF_BURST_ACK "EOB_ACK" /* EOB_ */
This is worse: it is not merely pointless, but pointless obfuscation, as the define doesn't exactly reflect the actual command as in the other cases.